gwenhywfar  5.10.1
mdigest.c
Go to the documentation of this file.
1 /***************************************************************************
2  begin : Wed Mar 16 2005
3  copyright : (C) 2005-2010 by Martin Preuss
4  email : martin@libchipcard.de
5 
6  ***************************************************************************
7  * Please see toplevel file COPYING for license details *
8  ***************************************************************************/
9 
10 #ifdef HAVE_CONFIG_H
11 # include <config.h>
12 #endif
13 
14 #define DISABLE_DEBUGLOG
15 
16 
17 #include "mdigest_p.h"
18 #include "i18n_l.h"
19 
20 #include <gwenhywfar/misc.h>
21 #include <gwenhywfar/debug.h>
22 #include <gwenhywfar/directory.h>
23 #include <gwenhywfar/text.h>
24 #include <gwenhywfar/syncio.h>
25 #include <gwenhywfar/syncio_file.h>
26 #include <gwenhywfar/gui.h>
27 
28 
29 
30 
32 GWEN_LIST_FUNCTIONS(GWEN_MDIGEST, GWEN_MDigest)
34 
35 
36 
37 
38 
40 {
41  GWEN_MDIGEST *md;
42 
44  md->refCount=1;
47 
48  md->hashAlgoId=a;
49  return md;
50 }
51 
52 
53 
55 {
56  if (md) {
57  assert(md->refCount);
58  if (md->refCount==1) {
60  free(md->pDigest);
61  md->refCount=0;
63  GWEN_FREE_OBJECT(md);
64  }
65  else
66  md->refCount--;
67  }
68 }
69 
70 
71 
73 {
74  assert(md);
75  assert(md->refCount);
76  return md->hashAlgoId;
77 }
78 
79 
80 
82 {
83  assert(md);
84  assert(md->refCount);
85  return md->pDigest;
86 }
87 
88 
89 
91 {
92  assert(md);
93  assert(md->refCount);
94  return md->lDigest;
95 }
96 
97 
98 
99 void GWEN_MDigest_SetDigestBuffer(GWEN_MDIGEST *md, uint8_t *buf, unsigned int l)
100 {
101  assert(md);
102  assert(md->refCount);
103 
104  if (l) {
105  assert(buf);
106  }
107 
108  if (md->pDigest && md->lDigest)
109  free(md->pDigest);
110  md->pDigest=buf;
111  md->lDigest=l;
112 }
113 
114 
115 
116 void GWEN_MDigest_SetDigestLen(GWEN_MDIGEST *md, unsigned int l)
117 {
118  assert(md);
119  assert(md->refCount);
120 
121  if (md->pDigest && md->lDigest)
122  free(md->pDigest);
123  md->pDigest=NULL;
124  md->lDigest=l;
125 }
126 
127 
128 
130 {
131  assert(md);
132  assert(md->refCount);
133  if (md->beginFn)
134  return md->beginFn(md);
135  else
137 }
138 
139 
140 
142 {
143  assert(md);
144  assert(md->refCount);
145  if (md->endFn)
146  return md->endFn(md);
147  else
149 }
150 
151 
152 
153 int GWEN_MDigest_Update(GWEN_MDIGEST *md, const uint8_t *buf, unsigned int l)
154 {
155  assert(md);
156  assert(md->refCount);
157  if (md->updateFn)
158  return md->updateFn(md, buf, l);
159  else
161 }
162 
163 
164 
166  const uint8_t *srcBuf, unsigned int srcLen,
167  uint8_t *dstBuf, unsigned int dstLen)
168 {
169  int rv;
170  int digestLen;
171 
172  assert(md);
173  assert(srcBuf && srcLen);
174  assert(dstBuf && dstLen);
175 
176  if (md && srcBuf && srcLen && dstBuf && dstLen) {
177  rv=GWEN_MDigest_Begin(md);
178  if (rv<0) {
179  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
180  return rv;
181  }
182  rv=GWEN_MDigest_Update(md, srcBuf, srcLen);
183  if (rv<0) {
184  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
185  return rv;
186  }
187  rv=GWEN_MDigest_End(md);
188  if (rv<0) {
189  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
190  return rv;
191  }
192  digestLen=GWEN_MDigest_GetDigestSize(md);
193  if (dstLen<digestLen) {
194  DBG_ERROR(GWEN_LOGDOMAIN, "Provided buffer too small (%d < %d)", dstLen, digestLen);
196  }
197 
198  memmove(dstBuf, GWEN_MDigest_GetDigestPtr(md), digestLen);
199  return 0;
200  }
201  else {
202  DBG_ERROR(GWEN_LOGDOMAIN, "Empty function arguments");
203  return GWEN_ERROR_INTERNAL;
204  }
205 }
206 
207 
208 
209 
210 
211 
212 
214 {
216 
217  assert(md);
218  assert(md->refCount);
219  of=md->beginFn;
220  md->beginFn=f;
221 
222  return of;
223 }
224 
225 
226 
228 {
230 
231  assert(md);
232  assert(md->refCount);
233  of=md->endFn;
234  md->endFn=f;
235 
236  return of;
237 }
238 
239 
240 
242 {
244 
245  assert(md);
246  assert(md->refCount);
247  of=md->updateFn;
248  md->updateFn=f;
249 
250  return of;
251 }
252 
253 
254 
256  const char *password,
257  const uint8_t *pSalt,
258  uint32_t lSalt,
259  uint8_t *pKey,
260  uint32_t lKey,
261  uint32_t iterations)
262 {
263  int rv;
264  uint8_t hash[128];
265  uint32_t hsize;
266  uint32_t i;
267 
268  hsize=GWEN_MDigest_GetDigestSize(md);
269  if (lKey>hsize || lKey>sizeof(hash)) {
270  DBG_ERROR(GWEN_LOGDOMAIN, "Derived key too long");
271  return GWEN_ERROR_INVALID;
272  }
273 
274  rv=GWEN_MDigest_Begin(md);
275  if (rv<0) {
276  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
277  GWEN_MDigest_End(md);
278  return rv;
279  }
280 
281  /* hash password */
282  rv=GWEN_MDigest_Update(md, (const uint8_t *) password, strlen(password));
283  if (rv<0) {
284  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
285  GWEN_MDigest_End(md);
286  return rv;
287  }
288 
289  /* hash salt */
290  rv=GWEN_MDigest_Update(md, pSalt, lSalt);
291  if (rv<0) {
292  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
293  GWEN_MDigest_End(md);
294  return rv;
295  }
296 
297  rv=GWEN_MDigest_End(md);
298  if (rv<0) {
299  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
300  GWEN_MDigest_End(md);
301  return rv;
302  }
303 
304  /* use that hash now for the iterations */
305  memmove(hash, GWEN_MDigest_GetDigestPtr(md), hsize);
306 
307  for (i=2; i<iterations; i++) {
308  rv=GWEN_MDigest_Begin(md);
309  if (rv<0) {
310  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
311  GWEN_MDigest_End(md);
312  return rv;
313  }
314  rv=GWEN_MDigest_Update(md, hash, hsize);
315  if (rv<0) {
316  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
317  GWEN_MDigest_End(md);
318  return rv;
319  }
320 
321  rv=GWEN_MDigest_End(md);
322  if (rv<0) {
323  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
324  GWEN_MDigest_End(md);
325  return rv;
326  }
327 
328  /* use that hash now for the next iteration */
329  memmove(hash, GWEN_MDigest_GetDigestPtr(md), hsize);
330  }
331 
332  /* done, copy key */
333  memmove(pKey, hash, lKey);
334  memset(hash, 0, sizeof(hash));
335 
336  return 0;
337 }
338 
339 
340 
342  const char *fname,
343  GWEN_BUFFER *hbuf)
344 {
345  GWEN_SYNCIO *sio;
346  int rv;
347  uint8_t buffer[1024];
348 
351  rv=GWEN_SyncIo_Connect(sio);
352  if (rv<0) {
353  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
354  GWEN_SyncIo_free(sio);
355  return rv;
356  }
357 
358  rv=GWEN_MDigest_Begin(md);
359  if (rv<0) {
360  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
362  GWEN_SyncIo_free(sio);
363  return rv;
364  }
365 
366  while (1) {
367  rv=GWEN_SyncIo_Read(sio, buffer, sizeof(buffer));
368  if (rv<0) {
369  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
371  GWEN_SyncIo_free(sio);
372  return rv;
373  }
374  else if (rv==0)
375  break;
376  else {
377  rv=GWEN_MDigest_Update(md, (const uint8_t *) buffer, rv);
378  if (rv<0) {
379  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
381  GWEN_SyncIo_free(sio);
382  return rv;
383  }
384  }
385  }
386 
387  rv=GWEN_MDigest_End(md);
388  if (rv<0) {
389  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
391  GWEN_SyncIo_free(sio);
392  return rv;
393  }
394 
396  GWEN_SyncIo_free(sio);
397 
398  rv=GWEN_Text_ToHexBuffer((const char *) GWEN_MDigest_GetDigestPtr(md),
400  hbuf, 0, 0, 0);
401  if (rv<0) {
402  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
403  return rv;
404  }
405 
406  return 0;
407 }
408 
409 
410 
412  const char *baseFolder,
413  const char *relFolder,
414  const char *ignoreFile,
415  GWEN_STRINGLIST *sl)
416 {
417  GWEN_STRINGLIST *files;
419  GWEN_BUFFER *pbuf;
420  uint32_t ppos;
421  uint32_t rpos;
422  int rv;
423 
424  files=GWEN_StringList_new();
425  pbuf=GWEN_Buffer_new(0, 256, 0, 1);
426  GWEN_Buffer_AppendString(pbuf, baseFolder);
428  rpos=GWEN_Buffer_GetPos(pbuf);
429  if (relFolder) {
430  GWEN_Buffer_AppendString(pbuf, relFolder);
432  }
433  ppos=GWEN_Buffer_GetPos(pbuf);
434 
436  if (rv<0) {
437  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
438  GWEN_Buffer_free(pbuf);
439  GWEN_StringList_free(files);
440  return rv;
441  }
442 
443  se=GWEN_StringList_FirstEntry(files);
444  while (se) {
445  const char *s;
446 
448  if (s && *s) {
449  GWEN_Buffer_AppendString(pbuf, s+1);
450  if (*s=='d') {
451  if (strcasecmp(s+1, ".")!=0 && strcasecmp(s+1, "..")!=0) {
453  baseFolder,
454  GWEN_Buffer_GetStart(pbuf)+rpos,
455  ignoreFile,
456  sl);
457  if (rv<0) {
458  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
459  GWEN_Buffer_free(pbuf);
460  GWEN_StringList_free(files);
461  return rv;
462  }
463  }
464  }
465  else if (*s=='f') {
466  if (!(ignoreFile && strcasecmp(ignoreFile, s+1)==0)) {
467  GWEN_BUFFER *tbuf;
468  GWEN_BUFFER *xbuf;
469  char *p;
470 
471  xbuf=GWEN_Buffer_new(0, 256, 0, 1);
473  p=GWEN_Buffer_GetStart(xbuf);
474  while (*p) {
475  if (*p=='\\')
476  *p='/';
477  p++;
478  }
479 
480  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
481 
482  /* add relative path to line buffer */
483  GWEN_Buffer_AppendString(tbuf, "F");
485  GWEN_Buffer_free(xbuf);
486  if (rv<0) {
487  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
488  GWEN_Buffer_free(tbuf);
489  GWEN_Buffer_free(pbuf);
490  GWEN_StringList_free(files);
491  return rv;
492  }
493  GWEN_Buffer_AppendString(tbuf, ":");
494 
495  /* hash file */
496  rv=GWEN_MDigest__HashFile(md, GWEN_Buffer_GetStart(pbuf), tbuf);
497  if (rv<0) {
498  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
499  GWEN_Buffer_free(tbuf);
500  GWEN_Buffer_free(pbuf);
501  GWEN_StringList_free(files);
502  return rv;
503  }
504 
505  /* append line to stringlist */
507  GWEN_Buffer_free(tbuf);
508  }
509  }
510  else {
511  DBG_INFO(GWEN_LOGDOMAIN, "Unknown file type in [%s]", s);
512  }
513  GWEN_Buffer_Crop(pbuf, 0, ppos);
514  }
516  }
517 
518  GWEN_Buffer_free(pbuf);
519  GWEN_StringList_free(files);
520  return 0;
521 }
522 
523 
524 
526  const char *folder,
527  const char *ignoreFile,
528  GWEN_STRINGLIST *sl)
529 {
530  int rv;
531 
532  rv=GWEN_MDigest__HashFileTree(md, folder, NULL, ignoreFile, sl);
533  if (rv<0) {
534  DBG_INFO(GWEN_LOGDOMAIN, "here (%d)", rv);
535  return rv;
536  }
537 
538  return 0;
539 }
540 
541 
542 
544  const char *folder,
545  const char *checksumFile,
546  int strictCheck,
547  uint32_t pid)
548 {
549  GWEN_STRINGLIST *sl;
550  GWEN_STRINGLIST *savedList;
551  GWEN_BUFFER *tbuf;
553  int rv;
554  int allHashesOk=1;
555  int validLines=0;
556 
557  sl=GWEN_StringList_new();
558 
559  /* generate hash list */
560  rv=GWEN_MDigest_HashFileTree(md, folder, checksumFile, sl);
561  if (rv<0) {
563  I18N("Error unpacking program (%d)"), rv);
565  return rv;
566  }
567 
568  savedList=GWEN_StringList_new();
569 
570  /* read checksums from file */
571  tbuf=GWEN_Buffer_new(0, 256, 0, 1);
572  GWEN_Buffer_AppendString(tbuf, folder);
574  GWEN_Buffer_AppendString(tbuf, checksumFile);
576  -1,
577  savedList);
578  if (rv<0) {
580  I18N("Error loading checksum file (%d)"), rv);
581  GWEN_Buffer_free(tbuf);
582  GWEN_StringList_free(savedList);
584  return rv;
585  }
586  GWEN_Buffer_free(tbuf);
587 
588  /* check checksums */
589  se=GWEN_StringList_FirstEntry(savedList);
590  while (se) {
591  const char *s;
592 
594  if (s && *s) {
595  validLines++;
596  if (0==GWEN_StringList_RemoveString(sl, s)) {
597  DBG_ERROR(0, "Hash not found: %s", s);
598  allHashesOk=0;
599  }
600  }
602  }
603 
604  if (validLines==0) {
606  I18N("Checksum file does not contain valid lines"));
607  GWEN_StringList_free(savedList);
609  return GWEN_ERROR_VERIFY;
610  }
611 
612  if (allHashesOk==0) {
614  I18N("Integrity check on folder failed"));
615  GWEN_StringList_free(savedList);
617  return GWEN_ERROR_VERIFY;
618  }
619 
620  /* check for additional files */
621  if (GWEN_StringList_Count(sl)) {
622  if (strictCheck) {
624  I18N("Folder contains %d files without checksum"),
626  GWEN_StringList_free(savedList);
628  }
629  else
631  I18N("Folder contains %d files without checksum"),
633  }
634  GWEN_StringList_free(savedList);
636 
637  return 0;
638 }
639 
640 
641 
642 
643 
644 
int(* GWEN_MDIGEST_UPDATE_FN)(GWEN_MDIGEST *md, const uint8_t *buf, unsigned int l)
Definition: mdigest_be.h:26
char * GWEN_Buffer_GetStart(const GWEN_BUFFER *bf)
Definition: buffer.c:235
#define I18N(m)
Definition: error.c:42
struct GWEN_STRINGLISTENTRYSTRUCT GWEN_STRINGLISTENTRY
Definition: stringlist.h:53
GWEN_CRYPT_HASHALGOID
Definition: hashalgo.h:48
#define GWEN_LIST2_FUNCTIONS(t, pr)
Definition: list2.h:99
int GWEN_SyncIo_Connect(GWEN_SYNCIO *sio)
Definition: syncio.c:97
void GWEN_MDigest_free(GWEN_MDIGEST *md)
Definition: mdigest.c:54
#define GWEN_INHERIT_FINI(t, element)
Definition: inherit.h:238
#define GWEN_ERROR_INVALID
Definition: error.h:67
#define GWEN_DIR_SEPARATOR_S
#define GWEN_SYNCIO_FILE_FLAGS_READ
Definition: syncio_file.h:53
int GWEN_SyncIo_Read(GWEN_SYNCIO *sio, uint8_t *buffer, uint32_t size)
Definition: syncio.c:133
GWEN_MDIGEST_END_FN GWEN_MDigest_SetEndFn(GWEN_MDIGEST *md, GWEN_MDIGEST_END_FN f)
Definition: mdigest.c:227
void GWEN_MDigest_SetDigestLen(GWEN_MDIGEST *md, unsigned int l)
Definition: mdigest.c:116
#define GWEN_FREE_OBJECT(varname)
Definition: memory.h:61
#define NULL
Definition: binreloc.c:300
GWEN_MDIGEST * GWEN_MDigest_new(GWEN_CRYPT_HASHALGOID a)
Definition: mdigest.c:39
int GWEN_MDigest_Digest(GWEN_MDIGEST *md, const uint8_t *srcBuf, unsigned int srcLen, uint8_t *dstBuf, unsigned int dstLen)
Definition: mdigest.c:165
GWEN_MDIGEST_UPDATE_FN GWEN_MDigest_SetUpdateFn(GWEN_MDIGEST *md, GWEN_MDIGEST_UPDATE_FN f)
Definition: mdigest.c:241
#define GWEN_LOGDOMAIN
Definition: logger.h:35
uint32_t GWEN_Buffer_GetPos(const GWEN_BUFFER *bf)
Definition: buffer.c:253
int GWEN_MDigest_Update(GWEN_MDIGEST *md, const uint8_t *buf, unsigned int l)
Definition: mdigest.c:153
GWEN_BUFFER * GWEN_Buffer_new(char *buffer, uint32_t size, uint32_t used, int take)
Definition: buffer.c:42
#define GWEN_ERROR_BUFFER_OVERFLOW
Definition: error.h:79
GWEN_STRINGLISTENTRY * GWEN_StringList_FirstEntry(const GWEN_STRINGLIST *sl)
Definition: stringlist.c:390
const char * GWEN_StringListEntry_Data(const GWEN_STRINGLISTENTRY *se)
Definition: stringlist.c:406
uint8_t * GWEN_MDigest_GetDigestPtr(GWEN_MDIGEST *md)
Definition: mdigest.c:81
void GWEN_StringList_free(GWEN_STRINGLIST *sl)
Definition: stringlist.c:62
int GWEN_MDigest_Begin(GWEN_MDIGEST *md)
Definition: mdigest.c:129
#define GWEN_NEW_OBJECT(typ, varname)
Definition: memory.h:55
struct GWEN_SYNCIO GWEN_SYNCIO
Definition: syncio.h:40
int(* GWEN_MDIGEST_END_FN)(GWEN_MDIGEST *md)
Definition: mdigest_be.h:25
int GWEN_MDigest_HashFileTree(GWEN_MDIGEST *md, const char *folder, const char *ignoreFile, GWEN_STRINGLIST *sl)
Definition: mdigest.c:525
int GWEN_StringList_AppendString(GWEN_STRINGLIST *sl, const char *s, int take, int checkDouble)
Definition: stringlist.c:245
int GWEN_SyncIo_Helper_ReadFileToStringList(const char *fname, int maxLines, GWEN_STRINGLIST *sl)
Definition: syncio.c:438
GWENHYWFAR_API int GWEN_Gui_ProgressLog2(uint32_t id, GWEN_LOGGER_LEVEL level, const char *text,...)
Definition: gui_virtual.c:458
int GWEN_MDigest_CheckFileTree(GWEN_MDIGEST *md, const char *folder, const char *checksumFile, int strictCheck, uint32_t pid)
Definition: mdigest.c:543
int GWEN_Text_EscapeToBuffer(const char *src, GWEN_BUFFER *buf)
Definition: text.c:1376
struct GWEN_STRINGLISTSTRUCT GWEN_STRINGLIST
Definition: stringlist.h:56
struct GWEN_MDIGEST GWEN_MDIGEST
Definition: mdigest.h:25
GWEN_CRYPT_HASHALGOID GWEN_MDigest_GetHashAlgoId(const GWEN_MDIGEST *md)
Definition: mdigest.c:72
int GWEN_StringList_RemoveString(GWEN_STRINGLIST *sl, const char *s)
Definition: stringlist.c:326
#define GWEN_INHERIT_INIT(t, element)
Definition: inherit.h:223
void GWEN_Buffer_free(GWEN_BUFFER *bf)
Definition: buffer.c:89
struct GWEN_BUFFER GWEN_BUFFER
A dynamically resizeable text buffer.
Definition: buffer.h:38
void GWEN_SyncIo_free(GWEN_SYNCIO *sio)
Definition: syncio.c:78
GWENHYWFAR_API int GWEN_Directory_GetFileEntriesWithType(const char *folder, GWEN_STRINGLIST *sl, const char *mask)
int GWEN_Buffer_Crop(GWEN_BUFFER *bf, uint32_t pos, uint32_t l)
Definition: buffer.c:947
unsigned int GWEN_StringList_Count(const GWEN_STRINGLIST *sl)
Definition: stringlist.c:427
int GWEN_MDigest_End(GWEN_MDIGEST *md)
Definition: mdigest.c:141
#define DBG_ERROR(dbg_logger, format, args...)
Definition: debug.h:97
int(* GWEN_MDIGEST_BEGIN_FN)(GWEN_MDIGEST *md)
Definition: mdigest_be.h:24
unsigned int GWEN_MDigest_GetDigestSize(GWEN_MDIGEST *md)
Definition: mdigest.c:90
int GWEN_SyncIo_Disconnect(GWEN_SYNCIO *sio)
Definition: syncio.c:109
void GWEN_SyncIo_SetFlags(GWEN_SYNCIO *sio, uint32_t fl)
Definition: syncio.c:170
static int GWEN_MDigest__HashFile(GWEN_MDIGEST *md, const char *fname, GWEN_BUFFER *hbuf)
Definition: mdigest.c:341
GWEN_STRINGLISTENTRY * GWEN_StringListEntry_Next(const GWEN_STRINGLISTENTRY *se)
Definition: stringlist.c:398
GWEN_MDIGEST_BEGIN_FN GWEN_MDigest_SetBeginFn(GWEN_MDIGEST *md, GWEN_MDIGEST_BEGIN_FN f)
Definition: mdigest.c:213
#define DBG_INFO(dbg_logger, format, args...)
Definition: debug.h:181
#define GWEN_LIST_INIT(t, element)
Definition: list1.h:465
#define GWEN_ERROR_VERIFY
Definition: error.h:104
GWENHYWFAR_API GWEN_SYNCIO * GWEN_SyncIo_File_new(const char *path, GWEN_SYNCIO_FILE_CREATIONMODE cm)
#define GWEN_LIST_FUNCTIONS(t, pr)
Definition: list1.h:366
#define GWEN_ERROR_INTERNAL
Definition: error.h:125
int GWEN_MDigest_PBKDF2(GWEN_MDIGEST *md, const char *password, const uint8_t *pSalt, uint32_t lSalt, uint8_t *pKey, uint32_t lKey, uint32_t iterations)
Definition: mdigest.c:255
void GWEN_MDigest_SetDigestBuffer(GWEN_MDIGEST *md, uint8_t *buf, unsigned int l)
Definition: mdigest.c:99
GWEN_STRINGLIST * GWEN_StringList_new(void)
Definition: stringlist.c:50
#define GWEN_LIST_FINI(t, element)
Definition: list1.h:474
#define GWEN_INHERIT_FUNCTIONS(t)
Definition: inherit.h:163
int GWEN_Text_ToHexBuffer(const char *src, unsigned l, GWEN_BUFFER *buf, unsigned int groupsize, char delimiter, int skipLeadingZeroes)
Definition: text.c:777
int GWEN_Buffer_AppendString(GWEN_BUFFER *bf, const char *buffer)
Definition: buffer.c:989
static int GWEN_MDigest__HashFileTree(GWEN_MDIGEST *md, const char *baseFolder, const char *relFolder, const char *ignoreFile, GWEN_STRINGLIST *sl)
Definition: mdigest.c:411
#define GWEN_ERROR_NOT_IMPLEMENTED
Definition: error.h:108