* eet: Use eina_log.
[framework/uifw/eet.git] / src / lib / eet_lib.c
1 /*
2  * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
3  */
4
5 #ifdef HAVE_CONFIG_H
6 # include <config.h>
7 #endif
8
9 #if defined(_WIN32) && ! defined(__CEGCC__)
10 # include <winsock2.h>
11 #endif
12
13 #ifdef HAVE_ALLOCA_H
14 # include <alloca.h>
15 #elif defined __GNUC__
16 # define alloca __builtin_alloca
17 #elif defined _AIX
18 # define alloca __alloca
19 #elif defined _MSC_VER
20 # include <malloc.h>
21 # define alloca _alloca
22 #else
23 # include <stddef.h>
24 # ifdef  __cplusplus
25 extern "C"
26 # endif
27 void *alloca (size_t);
28 #endif
29
30 #include <stdio.h>
31 #include <errno.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <sys/mman.h>
35 #include <time.h>
36 #include <string.h>
37 #include <fnmatch.h>
38 #include <fcntl.h>
39 #include <zlib.h>
40
41 #ifndef _MSC_VER
42 # include <unistd.h>
43 #endif
44
45 #ifdef HAVE_OPENSSL
46 #include <openssl/err.h>
47 #endif
48
49 #ifdef HAVE_NETINET_IN_H
50 # include <netinet/in.h>
51 #endif
52
53 #ifdef HAVE_EVIL
54 # include <Evil.h>
55 #endif
56
57 #ifdef HAVE_GNUTLS
58 # include <gnutls/gnutls.h>
59 # include <gcrypt.h>
60 #endif
61
62 #ifdef HAVE_OPENSSL
63 # include <openssl/err.h>
64 # include <openssl/evp.h>
65 #endif
66
67 #include <Eina.h>
68
69 #include "Eet.h"
70 #include "Eet_private.h"
71
72 #ifdef HAVE_REALPATH
73 # undef HAVE_REALPATH
74 #endif
75
76 #define EET_MAGIC_FILE                  0x1ee7ff00
77 #define EET_MAGIC_FILE_HEADER           0x1ee7ff01
78
79 #define EET_MAGIC_FILE2                 0x1ee70f42
80
81 typedef struct _Eet_File_Header         Eet_File_Header;
82 typedef struct _Eet_File_Node           Eet_File_Node;
83 typedef struct _Eet_File_Directory      Eet_File_Directory;
84
85 struct _Eet_File
86 {
87    char                 *path;
88    FILE                 *fp;
89    FILE                 *readfp;
90    Eet_File_Header      *header;
91    Eet_Dictionary       *ed;
92    Eet_Key              *key;
93    const unsigned char  *data;
94    const void           *x509_der;
95    const void           *signature;
96    void                 *sha1;
97
98    Eet_File_Mode         mode;
99
100    int                   magic;
101    int                   references;
102
103    int                   data_size;
104    int                   x509_length;
105    unsigned int          signature_length;
106    int                   sha1_length;
107
108    time_t                mtime;
109
110    unsigned char         writes_pending : 1;
111    unsigned char         delete_me_now : 1;
112 };
113
114 struct _Eet_File_Header
115 {
116    int                 magic;
117    Eet_File_Directory *directory;
118 };
119
120 struct _Eet_File_Directory
121 {
122    int             size;
123    Eet_File_Node **nodes;
124 };
125
126 struct _Eet_File_Node
127 {
128    char                 *name;
129    void                 *data;
130    Eet_File_Node        *next; /* FIXME: make buckets linked lists */
131
132    int                   offset;
133    int                   dictionary_offset;
134    int                   name_offset;
135
136    int                   name_size;
137    int                   size;
138    int                   data_size;
139
140    unsigned char         free_name : 1;
141    unsigned char         compression : 1;
142    unsigned char         ciphered : 1;
143 };
144
145
146 #if 0
147 /* Version 2 */
148 /* NB: all int's are stored in network byte order on disk */
149 /* file format: */
150 int magic; /* magic number ie 0x1ee7ff00 */
151 int num_directory_entries; /* number of directory entries to follow */
152 int bytes_directory_entries; /* bytes of directory entries to follow */
153 struct
154 {
155    int offset; /* bytes offset into file for data chunk */
156    int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
157    int size; /* size of the data chunk */
158    int data_size; /* size of the (uncompressed) data chunk */
159    int name_size; /* length in bytes of the name field */
160    char name[name_size]; /* name string (variable length) and \0 terminated */
161 } directory[num_directory_entries];
162 /* and now startes the data stream... */
163 #endif
164
165 #if 0
166 /* Version 3 */
167 /* NB: all int's are stored in network byte order on disk */
168 /* file format: */
169 int magic; /* magic number ie 0x1ee70f42 */
170 int num_directory_entries; /* number of directory entries to follow */
171 int num_dictionary_entries; /* number of dictionary entries to follow */
172 struct
173 {
174   int data_offset; /* bytes offset into file for data chunk */
175   int size; /* size of the data chunk */
176   int data_size; /* size of the (uncompressed) data chunk */
177   int name_offset; /* bytes offset into file for name string */
178   int name_size; /* length in bytes of the name field */
179   int flags; /* flags - for now 0 = uncompressed, 1 = compressed */
180 } directory[num_directory_entries];
181 struct
182 {
183   int hash;
184   int offset;
185   int size;
186   int prev;
187   int next;
188 } dictionary[num_dictionary_entries];
189 /* now start the string stream. */
190 /* and right after them the data stream. */
191 int magic_sign; /* Optional, only if the eet file is signed. */
192 int signature_length; /* Signature length. */
193 int x509_length; /* Public certificate that signed the file. */
194 char signature[signature_length]; /* The signature. */
195 char x509[x509_length]; /* The public certificate. */
196 #endif
197
198 #define EET_FILE2_HEADER_COUNT                  3
199 #define EET_FILE2_DIRECTORY_ENTRY_COUNT         6
200 #define EET_FILE2_DICTIONARY_ENTRY_COUNT        5
201
202 #define EET_FILE2_HEADER_SIZE                   (sizeof(int) * EET_FILE2_HEADER_COUNT)
203 #define EET_FILE2_DIRECTORY_ENTRY_SIZE          (sizeof(int) * EET_FILE2_DIRECTORY_ENTRY_COUNT)
204 #define EET_FILE2_DICTIONARY_ENTRY_SIZE         (sizeof(int) * EET_FILE2_DICTIONARY_ENTRY_COUNT)
205
206 /* prototypes of internal calls */
207 static Eet_File         *eet_cache_find(const char *path, Eet_File **cache, int cache_num);
208 static void             eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
209 static void             eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
210 static int              eet_string_match(const char *s1, const char *s2);
211 #if 0 /* Unused */
212 static Eet_Error        eet_flush(Eet_File *ef);
213 #endif
214 static Eet_Error        eet_flush2(Eet_File *ef);
215 static Eet_File_Node    *find_node_by_name(Eet_File *ef, const char *name);
216 static int              read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len);
217
218 /* cache. i don't expect this to ever be large, so arrays will do */
219 static int        eet_writers_num     = 0;
220 static int        eet_writers_alloc   = 0;
221 static Eet_File **eet_writers         = NULL;
222 static int        eet_readers_num     = 0;
223 static int        eet_readers_alloc   = 0;
224 static Eet_File **eet_readers         = NULL;
225 static int        eet_initcount       = 0;
226
227 /* log domain variable */
228 int _eet_log_dom_global=-1;
229
230 /* Check to see its' an eet file pointer */
231 static inline int
232 eet_check_pointer(const Eet_File *ef)
233 {
234   if ((!ef) || (ef->magic != EET_MAGIC_FILE))
235     return 1;
236   return 0;
237 }
238
239 static inline int
240 eet_check_header(const Eet_File *ef)
241 {
242    if (!ef->header)
243      return 1;
244    if (!ef->header->directory)
245      return 1;
246    return 0;
247 }
248
249 static inline int
250 eet_test_close(int test, Eet_File *ef)
251 {
252    if (test)
253      {
254         ef->delete_me_now = 1;
255         eet_close(ef);
256      }
257    return test;
258 }
259
260 /* find an eet file in the currently in use cache */
261 static Eet_File *
262 eet_cache_find(const char *path, Eet_File **cache, int cache_num)
263 {
264    int i;
265
266    /* walk list */
267    for (i = 0; i < cache_num; i++)
268      {
269         /* if matches real path - return it */
270         if (eet_string_match(cache[i]->path, path))
271           {
272              if (!cache[i]->delete_me_now)
273                return cache[i];
274           }
275      }
276
277    /* not found */
278    return NULL;
279 }
280
281 /* add to end of cache */
282 static void
283 eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
284 {
285    Eet_File     **new_cache;
286    int          new_cache_num;
287    int          new_cache_alloc;
288
289    new_cache_num = *cache_num;
290    if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
291      {
292         Eet_File        *del_ef = NULL;
293         int             i;
294
295         new_cache = *cache;
296         for (i = 0; i < new_cache_num; i++)
297           {
298              if (new_cache[i]->references == 0)
299                {
300                   del_ef = new_cache[i];
301                   break;
302                }
303           }
304
305         if (del_ef)
306           {
307              del_ef->delete_me_now = 1;
308              eet_close(del_ef);
309           }
310      }
311
312    new_cache = *cache;
313    new_cache_num = *cache_num;
314    new_cache_alloc = *cache_alloc;
315    new_cache_num++;
316    if (new_cache_num > new_cache_alloc)
317      {
318         new_cache_alloc += 16;
319         new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
320         if (!new_cache)
321           {
322              CRITICAL("BAD ERROR! Eet realloc of cache list failed. Abort\n");
323              abort();
324           }
325      }
326    new_cache[new_cache_num - 1] = ef;
327    *cache = new_cache;
328    *cache_num = new_cache_num;
329    *cache_alloc = new_cache_alloc;
330 }
331
332 /* delete from cache */
333 static void
334 eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
335 {
336    Eet_File **new_cache;
337    int new_cache_num, new_cache_alloc;
338    int i, j;
339
340    new_cache = *cache;
341    new_cache_num = *cache_num;
342    new_cache_alloc = *cache_alloc;
343    if (new_cache_num <= 0)
344      return;
345
346    for (i = 0; i < new_cache_num; i++)
347      {
348         if (new_cache[i] == ef)
349           break;
350      }
351
352    if (i >= new_cache_num)
353      return;
354
355    new_cache_num--;
356    for (j = i; j < new_cache_num; j++)
357      new_cache[j] = new_cache[j + 1];
358
359    if (new_cache_num <= (new_cache_alloc - 16))
360      {
361         new_cache_alloc -= 16;
362         if (new_cache_num > 0)
363           {
364              new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
365              if (!new_cache)
366                {
367                   CRITICAL("BAD ERROR! Eet realloc of cache list failed. Abort\n");
368                   abort();
369                }
370           }
371         else
372           {
373              free(new_cache);
374              new_cache = NULL;
375           }
376      }
377    *cache = new_cache;
378    *cache_num = new_cache_num;
379    *cache_alloc = new_cache_alloc;
380 }
381
382 /* internal string match. null friendly, catches same ptr */
383 static int
384 eet_string_match(const char *s1, const char *s2)
385 {
386    /* both null- no match */
387    if ((!s1) || (!s2)) return 0;
388    if (s1 == s2) return 1;
389    return (!strcmp(s1, s2));
390 }
391
392 /* flush out writes to a v2 eet file */
393 static Eet_Error
394 eet_flush2(Eet_File *ef)
395 {
396    Eet_File_Node        *efn;
397    Eet_Error             error = EET_ERROR_NONE;
398    int                   head[EET_FILE2_HEADER_COUNT];
399    int                   num_directory_entries = 0;
400    int                   num_dictionary_entries = 0;
401    int                   bytes_directory_entries = 0;
402    int                   bytes_dictionary_entries = 0;
403    int                   bytes_strings = 0;
404    int                   data_offset = 0;
405    int                   strings_offset = 0;
406    int                   num;
407    int                   i;
408    int                   j;
409
410    if (eet_check_pointer(ef))
411      return EET_ERROR_BAD_OBJECT;
412    if (eet_check_header(ef))
413      return EET_ERROR_EMPTY;
414    if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE))
415      return EET_ERROR_NOT_WRITABLE;
416    if (!ef->writes_pending)
417      return EET_ERROR_NONE;
418    if (ef->mode == EET_FILE_MODE_READ_WRITE && ef->fp == NULL)
419      {
420         int fd;
421
422         unlink(ef->path);
423         fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
424         ef->fp = fdopen(fd, "wb");
425         if (!ef->fp) return EET_ERROR_NOT_WRITABLE;
426         fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC);
427      }
428
429    /* calculate string base offset and data base offset */
430    num = (1 << ef->header->directory->size);
431    for (i = 0; i < num; ++i)
432      {
433         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
434           {
435              num_directory_entries++;
436              bytes_strings += strlen(efn->name) + 1;
437           }
438      }
439    if (ef->ed)
440      {
441         num_dictionary_entries = ef->ed->count;
442
443         for (i = 0; i < num_dictionary_entries; ++i)
444           bytes_strings += ef->ed->all[i].len;
445      }
446
447    /* calculate section bytes size */
448    bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
449    bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
450
451    /* calculate per entry offset */
452    strings_offset = bytes_directory_entries + bytes_dictionary_entries;
453    data_offset = bytes_directory_entries + bytes_dictionary_entries + bytes_strings;
454
455    for (i = 0; i < num; ++i)
456      {
457         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
458           {
459              efn->offset = data_offset;
460              data_offset += efn->size;
461
462              efn->name_offset = strings_offset;
463              strings_offset += efn->name_size;
464           }
465      }
466
467    /* calculate dictionary strings offset */
468    if (ef->ed)
469      ef->ed->offset = strings_offset;
470
471    /* go thru and write the header */
472    head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE2);
473    head[1] = (int) htonl ((unsigned int) num_directory_entries);
474    head[2] = (int) htonl ((unsigned int) num_dictionary_entries);
475
476    fseek(ef->fp, 0, SEEK_SET);
477    if (fwrite(head, sizeof (head), 1, ef->fp) != 1)
478      goto write_error;
479
480    /* write directories entry */
481    for (i = 0; i < num; i++)
482      {
483         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
484           {
485              unsigned int flag;
486              int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
487
488              flag = (efn->ciphered << 1) | efn->compression;
489
490              ibuf[0] = (int) htonl ((unsigned int) efn->offset);
491              ibuf[1] = (int) htonl ((unsigned int) efn->size);
492              ibuf[2] = (int) htonl ((unsigned int) efn->data_size);
493              ibuf[3] = (int) htonl ((unsigned int) efn->name_offset);
494              ibuf[4] = (int) htonl ((unsigned int) efn->name_size);
495              ibuf[5] = (int) htonl ((unsigned int) flag);
496
497              if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1)
498                goto write_error;
499           }
500      }
501
502    /* write dictionnary */
503    if (ef->ed)
504      {
505         int     offset = strings_offset;
506
507         for (j = 0; j < ef->ed->count; ++j)
508           {
509              int      sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
510
511              sbuf[0] = (int) htonl ((unsigned int) ef->ed->all[j].hash);
512              sbuf[1] = (int) htonl ((unsigned int) offset);
513              sbuf[2] = (int) htonl ((unsigned int) ef->ed->all[j].len);
514              sbuf[3] = (int) htonl ((unsigned int) ef->ed->all[j].prev);
515              sbuf[4] = (int) htonl ((unsigned int) ef->ed->all[j].next);
516
517              offset += ef->ed->all[j].len;
518
519              if (fwrite(sbuf, sizeof (sbuf), 1, ef->fp) != 1)
520                goto write_error;
521           }
522      }
523
524    /* write directories name */
525    for (i = 0; i < num; i++)
526      {
527         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
528           {
529              if (fwrite(efn->name, efn->name_size, 1, ef->fp) != 1)
530                goto write_error;
531           }
532      }
533
534    /* write strings */
535    if (ef->ed)
536      {
537         for (j = 0; j < ef->ed->count; ++j)
538           {
539              if (ef->ed->all[j].str)
540                {
541                   if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, ef->fp) != 1)
542                     goto write_error;
543                }
544              else
545                {
546                   if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, ef->fp) != 1)
547                     goto write_error;
548                }
549           }
550      }
551
552    /* write data */
553    for (i = 0; i < num; i++)
554      {
555         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
556           {
557              if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
558                goto write_error;
559           }
560      }
561
562    /* flush all write to the file. */
563    fflush(ef->fp);
564 // this is going to really cause trouble. if ANYTHING this needs to go into a
565 // thread spawned off - but even then...
566 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
567 // manual pages at eachother, but ext4 broke behavior that has been in place
568 // for decades and that 1000's of apps rely on daily - that is that one operation
569 // to disk is committed to disk BEFORE following operations, so the fs retains
570 // a consistent state
571 //   fsync(fileno(ef->fp));
572
573    /* append signature if required */
574    if (ef->key)
575      {
576         error = eet_identity_sign(ef->fp, ef->key);
577         if (error != EET_ERROR_NONE)
578           goto sign_error;
579      }
580
581    /* no more writes pending */
582    ef->writes_pending = 0;
583
584    return EET_ERROR_NONE;
585
586    write_error:
587    if (ferror(ef->fp))
588      {
589         switch (errno)
590           {
591            case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
592            case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
593            case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
594            case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
595            default: error = EET_ERROR_WRITE_ERROR; break;
596           }
597      }
598    sign_error:
599    if (ef->fp) fclose(ef->fp);
600    ef->fp = NULL;
601    return error;
602 }
603
604 #if 0 /* Unused */
605 /* flush out writes to an eet file */
606 static Eet_Error
607 eet_flush(Eet_File *ef)
608 {
609    Eet_File_Node        *efn;
610    int                  head[3];
611    int                  count = 0;
612    int                  size = 0;
613    int                  offset = 0;
614    int                  i;
615    int                  num;
616
617    /* check to see its' an eet file pointer */
618    if (eet_check_pointer(ef))
619      return EET_ERROR_BAD_OBJECT;
620    if (eet_check_header(ef))
621      return EET_ERROR_EMPTY;
622    if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE))
623      return EET_ERROR_NOT_WRITABLE;
624    if (!ef->writes_pending)
625      return EET_ERROR_NONE;
626
627    /* calculate total size in bytes of directory block */
628    num = (1 << ef->header->directory->size);
629    for (i = 0; i < num; i++)
630      {
631         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
632           {
633              size += 20 + strlen(efn->name) + 1;
634              count++;
635           }
636      }
637
638    /* calculate offsets per entry */
639    offset = 0;
640    for (i = 0; i < num; i++)
641      {
642         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
643           {
644              efn->offset = 12 + size + offset;
645              offset += efn->size;
646           }
647      }
648
649    /* go thru and write the header */
650    head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE);
651    head[1] = (int) htonl ((unsigned int) count);
652    head[2] = (int) htonl ((unsigned int) size);
653
654    fseek(ef->fp, 0, SEEK_SET);
655    if (fwrite(head, 12, 1, ef->fp) != 1)
656      goto write_error;
657
658    for (i = 0; i < num; i++)
659      {
660         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
661           {
662              unsigned int       ibuf[5];
663              int                name_size;
664
665              name_size = strlen(efn->name) + 1;
666
667              ibuf[0] = (int) htonl ((unsigned int) efn->offset);
668              ibuf[1] = (int) htonl ((unsigned int) efn->compression);
669              ibuf[2] = (int) htonl ((unsigned int) efn->size);
670              ibuf[3] = (int) htonl ((unsigned int) efn->data_size);
671              ibuf[4] = (int) htonl ((unsigned int) name_size);
672
673
674              if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1)
675                goto write_error;
676              if (fwrite(efn->name, name_size, 1, ef->fp) != 1)
677                goto write_error;
678           }
679      }
680
681    /* write data */
682    for (i = 0; i < num; i++)
683      {
684         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
685           {
686              if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
687                goto write_error;
688           }
689      }
690
691    /* no more writes pending */
692    ef->writes_pending = 0;
693
694    return EET_ERROR_NONE;
695
696    write_error:
697    if (ferror(ef->fp))
698      {
699         switch (errno)
700           {
701            case EFBIG:
702               fclose(ef->fp);
703               ef->fp = NULL;
704               return EET_ERROR_WRITE_ERROR_FILE_TOO_BIG;
705            case EIO:
706               fclose(ef->fp);
707               ef->fp = NULL;
708               return EET_ERROR_WRITE_ERROR_IO_ERROR;
709            case ENOSPC:
710               fclose(ef->fp);
711               ef->fp = NULL;
712               return EET_ERROR_WRITE_ERROR_OUT_OF_SPACE;
713            case EPIPE:
714               fclose(ef->fp);
715               ef->fp = NULL;
716               return EET_ERROR_WRITE_ERROR_FILE_CLOSED;
717            default:
718               fclose(ef->fp);
719               ef->fp = NULL;
720               return EET_ERROR_WRITE_ERROR;
721           }
722      }
723    sign_error:
724    if (ef->fp) fclose(ef->fp);
725    ef->fp = NULL;
726    return EET_ERROR_WRITE_ERROR;
727 }
728 #endif
729
730 EAPI int
731 eet_init(void)
732 {
733    eet_initcount++;
734
735    if (eet_initcount > 1) return eet_initcount;
736
737 #ifdef HAVE_GNUTLS
738    /* Before the library can be used, it must initialize itself if needed. */
739    if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0)
740      {
741         gcry_check_version(NULL);
742         /* Disable warning messages about problems with the secure memory subsystem.
743            This command should be run right after gcry_check_version. */
744         if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
745           return --eet_initcount;
746         /* This command is used to allocate a pool of secure memory and thus
747            enabling the use of secure memory. It also drops all extra privileges the
748            process has (i.e. if it is run as setuid (root)). If the argument nbytes
749            is 0, secure memory will be disabled. The minimum amount of secure memory
750            allocated is currently 16384 bytes; you may thus use a value of 1 to
751            request that default size. */
752         if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
753           fprintf(stderr, "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
754      }
755    if (gnutls_global_init())
756      return --eet_initcount;
757 #endif
758 #ifdef HAVE_OPENSSL
759    ERR_load_crypto_strings();
760    OpenSSL_add_all_algorithms();
761 #endif
762
763    if (!eina_init())
764      {
765        fprintf(stderr,"Eet: Eina init failed");
766        goto erro_eet_eina_init;
767      }
768    _eet_log_dom_global = eina_log_domain_register("Eet",EET_DEFAULT_LOG_COLOR);
769    if(_eet_log_dom_global < 0)
770      {
771        fprintf(stderr,"Eet Can not create a general log domain");
772        goto error_eet_eina_log;
773      }
774    return eet_initcount;
775  error_eet_eina_log:
776    eina_shutdown();
777  erro_eet_eina_init:
778 #ifdef HAVE_GNUTLS
779    gnutls_global_deinit();
780 #endif
781 #ifdef HAVE_OPENSSL
782    EVP_cleanup();
783    ERR_free_strings();
784 #endif
785    return 0;
786 }
787
788 EAPI int
789 eet_shutdown(void)
790 {
791    eet_initcount--;
792
793    if (eet_initcount > 0) return eet_initcount;
794
795    eet_clearcache();
796    eina_log_domain_unregister(_eet_log_dom_global);
797    eina_shutdown();
798 #ifdef HAVE_GNUTLS
799    gnutls_global_deinit();
800 #endif
801 #ifdef HAVE_OPENSSL
802    EVP_cleanup();
803    ERR_free_strings();
804 #endif
805
806    return eet_initcount;
807 }
808
809 EAPI void
810 eet_clearcache(void)
811 {
812    int  num = 0;
813    int  i;
814
815    /*
816     * We need to compute the list of eet file to close separately from the cache,
817     * due to eet_close removing them from the cache after each call.
818     */
819    for (i = 0; i < eet_writers_num; i++)
820      {
821         if (eet_writers[i]->references <= 0) num++;
822      }
823
824    for (i = 0; i < eet_readers_num; i++)
825      {
826         if (eet_readers[i]->references <= 0) num++;
827      }
828
829    if (num > 0)
830      {
831         Eet_File **closelist = NULL;
832
833         closelist = alloca(num * sizeof(Eet_File *));
834         num = 0;
835         for (i = 0; i < eet_writers_num; i++)
836           {
837              if (eet_writers[i]->references <= 0)
838                {
839                   closelist[num] = eet_writers[i];
840                   eet_writers[i]->delete_me_now = 1;
841                   num++;
842                }
843           }
844
845         for (i = 0; i < eet_readers_num; i++)
846           {
847              if (eet_readers[i]->references <= 0)
848                {
849                   closelist[num] = eet_readers[i];
850                   eet_readers[i]->delete_me_now = 1;
851                   num++;
852                }
853           }
854
855         for (i = 0; i < num; i++)
856           {
857              eet_close(closelist[i]);
858           }
859      }
860 }
861
862 /* FIXME: MMAP race condition in READ_WRITE_MODE */
863 static Eet_File *
864 eet_internal_read2(Eet_File *ef)
865 {
866    const int    *data = (const int*) ef->data;
867    const char   *start = (const char*) ef->data;
868    int           index = 0;
869    int           num_directory_entries;
870    int           bytes_directory_entries;
871    int           num_dictionary_entries;
872    int           bytes_dictionary_entries;
873    int           signature_base_offset;
874    int           i;
875
876    index += sizeof(int);
877    if (eet_test_close((int) ntohl(*data) != EET_MAGIC_FILE2, ef))
878      return NULL;
879    data++;
880
881 #define GET_INT(Value, Pointer, Index)          \
882    {                                            \
883       Value = ntohl(*Pointer);                  \
884       Pointer++;                                \
885       Index += sizeof(int);                     \
886    }
887
888    /* get entries count and byte count */
889    GET_INT(num_directory_entries, data, index);
890    /* get dictionary count and byte count */
891    GET_INT(num_dictionary_entries, data, index);
892
893    bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
894    bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
895
896    /* we cant have <= 0 values here - invalid */
897    if (eet_test_close((num_directory_entries <= 0), ef))
898      return NULL;
899
900    /* we cant have more bytes directory and bytes in dictionaries than the size of the file */
901    if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) > ef->data_size, ef))
902      return NULL;
903
904    /* allocate header */
905    ef->header = calloc(1, sizeof(Eet_File_Header));
906    if (eet_test_close(!ef->header, ef))
907      return NULL;
908
909    ef->header->magic = EET_MAGIC_FILE_HEADER;
910
911    /* allocate directory block in ram */
912    ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
913    if (eet_test_close(!ef->header->directory, ef))
914      return NULL;
915
916    /* 8 bit hash table (256 buckets) */
917    ef->header->directory->size = 8;
918    /* allocate base hash table */
919    ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
920    if (eet_test_close(!ef->header->directory->nodes, ef))
921      return NULL;
922
923    signature_base_offset = 0;
924
925    /* actually read the directory block - all of it, into ram */
926    for (i = 0; i < num_directory_entries; ++i)
927      {
928         const char      *name;
929         Eet_File_Node   *efn;
930         int              name_offset;
931         int              name_size;
932         int              hash;
933         int              flag;
934
935         /* out directory block is inconsistent - we have oveerun our */
936         /* dynamic block buffer before we finished scanning dir entries */
937         efn = malloc (sizeof(Eet_File_Node));
938         if (eet_test_close(!efn, ef))
939           return NULL;
940
941         /* get entrie header */
942         GET_INT(efn->offset, data, index);
943         GET_INT(efn->size, data, index);
944         GET_INT(efn->data_size, data, index);
945         GET_INT(name_offset, data, index);
946         GET_INT(name_size, data, index);
947         GET_INT(flag, data, index);
948
949         efn->compression = flag & 0x1 ? 1 : 0;
950         efn->ciphered = flag & 0x2 ? 1 : 0;
951
952 #define EFN_TEST(Test, Ef, Efn)                 \
953         if (eet_test_close(Test, Ef))           \
954           {                                     \
955              free(Efn);                         \
956              return NULL;                       \
957           }
958
959         /* check data pointer position */
960         EFN_TEST(!((efn->size > 0)
961                    && (efn->offset + efn->size <= ef->data_size)
962                    && (efn->offset > bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
963
964         /* check name position */
965         EFN_TEST(!((name_size > 0)
966                    && (name_offset + name_size < ef->data_size)
967                    && (name_offset >= bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
968
969         name = start + name_offset;
970
971         /* check '\0' at the end of name string */
972         EFN_TEST(name[name_size - 1] != '\0', ef, efn);
973
974         efn->free_name = 0;
975         efn->name = (char*) name;
976         efn->name_size = name_size;
977
978         hash = _eet_hash_gen(efn->name, ef->header->directory->size);
979         efn->next = ef->header->directory->nodes[hash];
980         ef->header->directory->nodes[hash] = efn;
981
982         /* read-only mode, so currently we have no data loaded */
983         if (ef->mode == EET_FILE_MODE_READ)
984           efn->data = NULL;
985         /* read-write mode - read everything into ram */
986         else
987           {
988              efn->data = malloc(efn->size);
989              if (efn->data)
990                memcpy(efn->data, ef->data + efn->offset, efn->size);
991           }
992
993         /* compute the possible position of a signature */
994         if (signature_base_offset < efn->offset + efn->size)
995           signature_base_offset = efn->offset + efn->size;
996      }
997
998    ef->ed = NULL;
999
1000    if (num_dictionary_entries)
1001      {
1002         const int       *dico = (const int*) ef->data + EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries + EET_FILE2_HEADER_COUNT;
1003         int              j;
1004
1005         if (eet_test_close((num_dictionary_entries * (int) EET_FILE2_DICTIONARY_ENTRY_SIZE + index) > (bytes_dictionary_entries + bytes_directory_entries), ef))
1006             return NULL;
1007
1008         ef->ed = calloc(1, sizeof (Eet_Dictionary));
1009         if (eet_test_close(!ef->ed, ef)) return NULL;
1010
1011         ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1012         if (eet_test_close(!ef->ed->all, ef)) return NULL;
1013
1014         ef->ed->count = num_dictionary_entries;
1015         ef->ed->total = num_dictionary_entries;
1016         ef->ed->start = start + bytes_dictionary_entries + bytes_directory_entries;
1017         ef->ed->end = ef->ed->start;
1018
1019         for (j = 0; j < ef->ed->count; ++j)
1020           {
1021              int   hash;
1022              int   offset;
1023
1024              GET_INT(hash, dico, index);
1025              GET_INT(offset, dico, index);
1026              GET_INT(ef->ed->all[j].len, dico, index);
1027              GET_INT(ef->ed->all[j].prev, dico, index);
1028              GET_INT(ef->ed->all[j].next, dico, index);
1029
1030              /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1031                 So stick to int and check the value. */
1032              if (eet_test_close(hash & 0xFFFFFF00, ef)) return NULL;
1033
1034              /* Check string position */
1035              if (eet_test_close(!((ef->ed->all[j].len > 0)
1036                                   && (offset > (bytes_dictionary_entries + bytes_directory_entries))
1037                                   && (offset + ef->ed->all[j].len < ef->data_size)), ef))
1038                return NULL;
1039
1040              ef->ed->all[j].mmap = start + offset;
1041              ef->ed->all[j].str = NULL;
1042
1043              if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
1044                ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
1045
1046              /* Check '\0' at the end of the string */
1047              if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] != '\0', ef)) return NULL;
1048
1049              ef->ed->all[j].hash = hash;
1050              if (ef->ed->all[j].prev == -1)
1051                ef->ed->hash[hash] = j;
1052
1053              /* compute the possible position of a signature */
1054              if (signature_base_offset < offset + ef->ed->all[j].len)
1055                signature_base_offset = offset + ef->ed->all[j].len;
1056           }
1057      }
1058
1059    /* Check if the file is signed */
1060    ef->x509_der = NULL;
1061    ef->x509_length = 0;
1062    ef->signature = NULL;
1063    ef->signature_length = 0;
1064
1065    if (signature_base_offset < ef->data_size)
1066      {
1067 #ifdef HAVE_SIGNATURE
1068         const unsigned char *buffer = ((const unsigned char*) ef->data) + signature_base_offset;
1069         ef->x509_der = eet_identity_check(ef->data, signature_base_offset,
1070                                           &ef->sha1, &ef->sha1_length,
1071                                           buffer, ef->data_size - signature_base_offset,
1072                                           &ef->signature, &ef->signature_length,
1073                                           &ef->x509_length);
1074
1075         if (eet_test_close(ef->x509_der == NULL, ef)) return NULL;
1076 #else
1077         ERROR("This file could be signed but you didn't compile the necessary code to check the signature.\n");
1078 #endif
1079      }
1080
1081    return ef;
1082 }
1083
1084 #if EET_OLD_EET_FILE_FORMAT
1085 static Eet_File *
1086 eet_internal_read1(Eet_File *ef)
1087 {
1088    const unsigned char  *dyn_buf = NULL;
1089    const unsigned char  *p = NULL;
1090    int                   index = 0;
1091    int                   num_entries;
1092    int                   byte_entries;
1093    int                   i;
1094
1095    WARN("EET file format of '%s' is deprecated. You should just open it one time with mode == EET_FILE_MODE_READ_WRITE to solve this issue.\n", ef->path);
1096
1097    /* build header table if read mode */
1098    /* geat header */
1099    index += sizeof(int);
1100    if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1101      return NULL;
1102
1103 #define EXTRACT_INT(Value, Pointer, Index) \
1104         { \
1105            int tmp; \
1106            memcpy(&tmp, Pointer + Index, sizeof(int)); \
1107            Value = ntohl(tmp); \
1108            Index += sizeof(int); \
1109         }
1110
1111    /* get entries count and byte count */
1112    EXTRACT_INT(num_entries, ef->data, index);
1113    EXTRACT_INT(byte_entries, ef->data, index);
1114
1115    /* we cant have <= 0 values here - invalid */
1116    if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1117      return NULL;
1118
1119    /* we can't have more entires than minimum bytes for those! invalid! */
1120    if (eet_test_close((num_entries * 20) > byte_entries, ef))
1121      return NULL;
1122
1123    /* check we will not outrun the file limit */
1124    if (eet_test_close(((byte_entries + (int) sizeof(int) * 3) > ef->data_size), ef))
1125      return NULL;
1126
1127    /* allocate header */
1128    ef->header = calloc(1, sizeof(Eet_File_Header));
1129    if (eet_test_close(!ef->header, ef))
1130      return NULL;
1131
1132    ef->header->magic = EET_MAGIC_FILE_HEADER;
1133
1134    /* allocate directory block in ram */
1135    ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1136    if (eet_test_close(!ef->header->directory, ef))
1137      return NULL;
1138
1139    /* 8 bit hash table (256 buckets) */
1140    ef->header->directory->size = 8;
1141    /* allocate base hash table */
1142    ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1143    if (eet_test_close(!ef->header->directory->nodes, ef))
1144      return NULL;
1145
1146    /* actually read the directory block - all of it, into ram */
1147    dyn_buf = ef->data + index;
1148
1149    /* parse directory block */
1150    p = dyn_buf;
1151
1152    for (i = 0; i < num_entries; i++)
1153      {
1154         Eet_File_Node   *efn;
1155         void            *data = NULL;
1156         int             indexn = 0;
1157         int             name_size;
1158         int             hash;
1159         int             k;
1160
1161 #define HEADER_SIZE (sizeof(int) * 5)
1162
1163         /* out directory block is inconsistent - we have oveerun our */
1164         /* dynamic block buffer before we finished scanning dir entries */
1165         if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1166           return NULL;
1167
1168         /* allocate all the ram needed for this stored node accounting */
1169         efn = malloc (sizeof(Eet_File_Node));
1170         if (eet_test_close(!efn, ef))
1171           return NULL;
1172
1173         /* get entrie header */
1174         EXTRACT_INT(efn->offset, p, indexn);
1175         EXTRACT_INT(efn->compression, p, indexn);
1176         EXTRACT_INT(efn->size, p, indexn);
1177         EXTRACT_INT(efn->data_size, p, indexn);
1178         EXTRACT_INT(name_size, p, indexn);
1179
1180         efn->name_size = name_size;
1181         efn->ciphered = 0;
1182
1183         /* invalid size */
1184         if (eet_test_close(efn->size <= 0, ef))
1185           {
1186              free (efn);
1187              return NULL;
1188           }
1189
1190         /* invalid name_size */
1191         if (eet_test_close(name_size <= 0, ef))
1192           {
1193              free (efn);
1194              return NULL;
1195           }
1196
1197         /* reading name would mean falling off end of dyn_buf - invalid */
1198         if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1199           {
1200              free (efn);
1201              return NULL;
1202           }
1203
1204         /* This code is useless if we dont want backward compatibility */
1205         for (k = name_size; k > 0 && ((unsigned char) * (p + HEADER_SIZE + k)) != 0; --k)
1206           ;
1207
1208         efn->free_name = ((unsigned char) * (p + HEADER_SIZE + k)) != 0;
1209
1210         if (efn->free_name)
1211           {
1212              efn->name = malloc(sizeof(char) * name_size + 1);
1213              if (eet_test_close(efn->name == NULL, ef))
1214                {
1215                   free (efn);
1216                   return NULL;
1217                }
1218
1219              strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1220              efn->name[name_size] = 0;
1221
1222              WARN("File: %s is not up to date for key \"%s\" - needs rebuilding sometime\n", ef->path, efn->name);
1223           }
1224         else
1225           /* The only really usefull peace of code for efn->name (no backward compatibility) */
1226           efn->name = (char*)((unsigned char*)(p + HEADER_SIZE));
1227
1228         /* get hash bucket it should go in */
1229         hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1230         efn->next = ef->header->directory->nodes[hash];
1231         ef->header->directory->nodes[hash] = efn;
1232
1233         /* read-only mode, so currently we have no data loaded */
1234         if (ef->mode == EET_FILE_MODE_READ)
1235           efn->data = NULL;
1236         /* read-write mode - read everything into ram */
1237         else
1238           {
1239              data = malloc(efn->size);
1240              if (data)
1241                memcpy(data, ef->data + efn->offset, efn->size);
1242              efn->data = data;
1243           }
1244         /* advance */
1245         p += HEADER_SIZE + name_size;
1246      }
1247    return ef;
1248 }
1249 #endif
1250
1251 static Eet_File *
1252 eet_internal_read(Eet_File *ef)
1253 {
1254    const int    *data = (const int*) ef->data;
1255
1256    if (eet_test_close((ef->data == (void *)-1) || (ef->data == NULL), ef))
1257      return NULL;
1258
1259    if (eet_test_close(ef->data_size < (int) sizeof(int) * 3, ef))
1260      return NULL;
1261
1262    switch (ntohl(*data))
1263      {
1264 #if EET_OLD_EET_FILE_FORMAT
1265       case EET_MAGIC_FILE:
1266         return eet_internal_read1(ef);
1267 #endif
1268       case EET_MAGIC_FILE2:
1269         return eet_internal_read2(ef);
1270       default:
1271         ef->delete_me_now = 1;
1272         eet_close(ef);
1273         break;
1274      }
1275
1276    return NULL;
1277 }
1278
1279 EAPI Eet_File *
1280 eet_memopen_read(const void *data, size_t size)
1281 {
1282    Eet_File     *ef;
1283
1284    if (data == NULL || size == 0)
1285      return NULL;
1286
1287    ef = malloc (sizeof (Eet_File));
1288    if (!ef)
1289      return NULL;
1290
1291    ef->ed = NULL;
1292    ef->path = NULL;
1293    ef->key = NULL;
1294    ef->magic = EET_MAGIC_FILE;
1295    ef->references = 1;
1296    ef->mode = EET_FILE_MODE_READ;
1297    ef->header = NULL;
1298    ef->mtime = 0;
1299    ef->delete_me_now = 1;
1300    ef->fp = NULL;
1301    ef->readfp = NULL;
1302    ef->data = data;
1303    ef->data_size = size;
1304    ef->sha1 = NULL;
1305    ef->sha1_length = 0;
1306
1307    return eet_internal_read(ef);
1308 }
1309
1310 EAPI Eet_File *
1311 eet_open(const char *file, Eet_File_Mode mode)
1312 {
1313    FILE         *fp;
1314    Eet_File     *ef;
1315    int           file_len;
1316    struct stat   file_stat;
1317
1318    if (!file)
1319      return NULL;
1320
1321    /* find the current file handle in cache*/
1322    ef = NULL;
1323    if (mode == EET_FILE_MODE_READ)
1324      {
1325         ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1326         if (ef)
1327           {
1328              eet_flush2(ef);
1329              ef->references++;
1330              ef->delete_me_now = 1;
1331              eet_close(ef);
1332           }
1333         ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1334      }
1335    else if ((mode == EET_FILE_MODE_WRITE) ||
1336             (mode == EET_FILE_MODE_READ_WRITE))
1337      {
1338         ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1339         if (ef)
1340           {
1341              ef->delete_me_now = 1;
1342              ef->references++;
1343              eet_close(ef);
1344           }
1345         ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1346      }
1347
1348     /* try open the file based on mode */
1349    if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1350      {
1351         fp = fopen(file, "rb");
1352         if (!fp) goto on_error;
1353         if (fstat(fileno(fp), &file_stat))
1354           {
1355              fclose(fp);
1356              fp = NULL;
1357              goto on_error;
1358           }
1359         if ((mode == EET_FILE_MODE_READ) &&
1360             (file_stat.st_size < ((int) sizeof(int) * 3)))
1361           {
1362              fclose(fp);
1363              fp = NULL;
1364              goto on_error;
1365           }
1366
1367      on_error:
1368         if (fp == NULL && mode == EET_FILE_MODE_READ) return NULL;
1369      }
1370    else
1371      {
1372         int fd;
1373
1374         if (mode != EET_FILE_MODE_WRITE) return NULL;
1375         memset(&file_stat, 0, sizeof(file_stat));
1376         /* opening for write - delete old copy of file right away */
1377         unlink(file);
1378         fd = open(file, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
1379         fp = fdopen(fd, "wb");
1380         if (!fp) return NULL;
1381      }
1382
1383    /* We found one */
1384    if (ef && (file_stat.st_mtime != ef->mtime))
1385      {
1386         ef->delete_me_now = 1;
1387         ef->references++;
1388         eet_close(ef);
1389         ef = NULL;
1390      }
1391
1392    if (ef)
1393      {
1394         /* reference it up and return it */
1395         if (fp != NULL) fclose(fp);
1396         ef->references++;
1397         return ef;
1398      }
1399
1400    file_len = strlen(file) + 1;
1401
1402    /* Allocate struct for eet file and have it zero'd out */
1403    ef = malloc(sizeof(Eet_File) + file_len);
1404    if (!ef)
1405      return NULL;
1406
1407    /* fill some of the members */
1408    ef->fp = fp;
1409    ef->key = NULL;
1410    ef->readfp = NULL;
1411    ef->path = ((char *)ef) + sizeof(Eet_File);
1412    memcpy(ef->path, file, file_len);
1413    ef->magic = EET_MAGIC_FILE;
1414    ef->references = 1;
1415    ef->mode = mode;
1416    ef->header = NULL;
1417    ef->mtime = file_stat.st_mtime;
1418    ef->writes_pending = 0;
1419    ef->delete_me_now = 0;
1420    ef->data = NULL;
1421    ef->data_size = 0;
1422    ef->sha1 = NULL;
1423    ef->sha1_length = 0;
1424
1425    ef->ed = (mode == EET_FILE_MODE_WRITE)
1426      || (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
1427      eet_dictionary_add() : NULL;
1428
1429    if (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) goto empty_file;
1430
1431    /* if we can't open - bail out */
1432    if (eet_test_close(!ef->fp, ef))
1433      return NULL;
1434
1435    fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC);
1436    /* if we opened for read or read-write */
1437    if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1438      {
1439         ef->data_size = file_stat.st_size;
1440         ef->data = mmap(NULL, ef->data_size, PROT_READ,
1441                         MAP_SHARED, fileno(ef->fp), 0);
1442         if (eet_test_close((ef->data == MAP_FAILED), ef))
1443           return NULL;
1444         ef = eet_internal_read(ef);
1445         if (!ef)
1446           return NULL;
1447      }
1448
1449  empty_file:
1450    /* we need to delete the original file in read-write mode and re-open for writing */
1451    if (ef->mode == EET_FILE_MODE_READ_WRITE)
1452      {
1453         ef->readfp = ef->fp;
1454         ef->fp = NULL;
1455      }
1456
1457    /* add to cache */
1458    if (ef->references == 1)
1459      {
1460         if (ef->mode == EET_FILE_MODE_READ)
1461           eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1462         else
1463           if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1464             eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1465      }
1466
1467    return ef;
1468 }
1469
1470 EAPI Eet_File_Mode
1471 eet_mode_get(Eet_File *ef)
1472 {
1473    /* check to see its' an eet file pointer */
1474    if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1475      return EET_FILE_MODE_INVALID;
1476    else
1477      return ef->mode;
1478 }
1479
1480 EAPI const void *
1481 eet_identity_x509(Eet_File *ef, int *der_length)
1482 {
1483    if (!ef->x509_der) return NULL;
1484
1485    if (der_length) *der_length = ef->x509_length;
1486    return ef->x509_der;
1487 }
1488
1489 EAPI const void *
1490 eet_identity_signature(Eet_File *ef, int *signature_length)
1491 {
1492    if (!ef->signature) return NULL;
1493
1494    if (signature_length) *signature_length = ef->signature_length;
1495    return ef->signature;
1496 }
1497
1498 EAPI const void *
1499 eet_identity_sha1(Eet_File *ef, int *sha1_length)
1500 {
1501    if (!ef->sha1)
1502      ef->sha1 = eet_identity_compute_sha1(ef->data, ef->data_size, &ef->sha1_length);
1503
1504    if (sha1_length) *sha1_length = ef->sha1_length;
1505    return ef->sha1;
1506 }
1507
1508 EAPI Eet_Error
1509 eet_identity_set(Eet_File *ef, Eet_Key *key)
1510 {
1511    Eet_Key *tmp = ef->key;
1512
1513    if (!ef) return EET_ERROR_BAD_OBJECT;
1514
1515    ef->key = key;
1516    eet_identity_ref(ef->key);
1517    eet_identity_unref(tmp);
1518
1519    /* flags that writes are pending */
1520    ef->writes_pending = 1;
1521
1522    return EET_ERROR_NONE;
1523 }
1524
1525 EAPI Eet_Error
1526 eet_close(Eet_File *ef)
1527 {
1528    Eet_Error err;
1529
1530    /* check to see its' an eet file pointer */
1531    if (eet_check_pointer(ef))
1532      return EET_ERROR_BAD_OBJECT;
1533    /* deref */
1534    ef->references--;
1535    /* if its still referenced - dont go any further */
1536    if (ef->references > 0) return EET_ERROR_NONE;
1537    /* flush any writes */
1538    err = eet_flush2(ef);
1539
1540    eet_identity_unref(ef->key);
1541    ef->key = NULL;
1542
1543    /* if not urgent to delete it - dont free it - leave it in cache */
1544    if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1545      return EET_ERROR_NONE;
1546
1547    /* remove from cache */
1548    if (ef->mode == EET_FILE_MODE_READ)
1549      eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1550    else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1551      eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1552
1553    /* free up data */
1554    if (ef->header)
1555      {
1556         if (ef->header->directory)
1557           {
1558              if (ef->header->directory->nodes)
1559                {
1560                   int i, num;
1561
1562                   num = (1 << ef->header->directory->size);
1563                   for (i = 0; i < num; i++)
1564                     {
1565                        Eet_File_Node *efn;
1566
1567                        while ((efn = ef->header->directory->nodes[i]))
1568                          {
1569                             if (efn->data)
1570                               free(efn->data);
1571
1572                             ef->header->directory->nodes[i] = efn->next;
1573
1574                             if (efn->free_name)
1575                               free(efn->name);
1576
1577                             free(efn);
1578                          }
1579                     }
1580                   free(ef->header->directory->nodes);
1581                }
1582              free(ef->header->directory);
1583           }
1584         free(ef->header);
1585      }
1586
1587    eet_dictionary_free(ef->ed);
1588
1589    if (ef->sha1) free(ef->sha1);
1590    if (ef->data) munmap((void*)ef->data, ef->data_size);
1591    if (ef->fp) fclose(ef->fp);
1592    if (ef->readfp) fclose(ef->readfp);
1593
1594    /* zero out ram for struct - caution tactic against stale memory use */
1595    memset(ef, 0, sizeof(Eet_File));
1596
1597    /* free it */
1598    free(ef);
1599    return err;
1600 }
1601
1602 EAPI void *
1603 eet_read_cipher(Eet_File *ef, const char *name, int *size_ret, const char *cipher_key)
1604 {
1605    void                 *data = NULL;
1606    int                  size = 0;
1607    Eet_File_Node        *efn;
1608
1609    if (size_ret)
1610      *size_ret = 0;
1611
1612    /* check to see its' an eet file pointer */
1613    if (eet_check_pointer(ef))
1614      return NULL;
1615    if (!name)
1616      return NULL;
1617    if ((ef->mode != EET_FILE_MODE_READ) &&
1618        (ef->mode != EET_FILE_MODE_READ_WRITE))
1619      return NULL;
1620
1621    /* no header, return NULL */
1622    if (eet_check_header(ef))
1623      return NULL;
1624
1625    /* hunt hash bucket */
1626    efn = find_node_by_name(ef, name);
1627    if (!efn)
1628      return NULL;
1629
1630    /* get size (uncompressed, if compressed at all) */
1631    size = efn->data_size;
1632
1633    /* allocate data */
1634    data = malloc(size);
1635    if (!data)
1636      return NULL;
1637
1638    /* uncompressed data */
1639    if (efn->compression == 0)
1640      {
1641         void *data_deciphered = NULL;
1642         unsigned int data_deciphered_sz = 0;
1643         /* if we alreayd have the data in ram... copy that */
1644         if (efn->data)
1645           memcpy(data, efn->data, efn->size);
1646         else
1647           if (!read_data_from_disk(ef, efn, data, size))
1648             {
1649                free(data);
1650                return NULL;
1651             }
1652         if (efn->ciphered && cipher_key)
1653           {
1654             if (eet_decipher(data, size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
1655               {
1656                 free(data);
1657                 if (data_deciphered) free(data_deciphered);
1658                 return NULL;
1659               }
1660             free(data);
1661             data = data_deciphered;
1662             size = data_deciphered_sz;
1663           }
1664      }
1665    /* compressed data */
1666    else
1667      {
1668         void    *tmp_data;
1669         void    *data_deciphered = NULL;
1670         unsigned int data_deciphered_sz = 0;
1671         int     free_tmp = 0;
1672         int     compr_size = efn->size;
1673         uLongf  dlen;
1674
1675         /* if we already have the data in ram... copy that */
1676         if (efn->data)
1677           tmp_data = efn->data;
1678         else
1679           {
1680              tmp_data = malloc(compr_size);
1681              if (!tmp_data)
1682                {
1683                   free(data);
1684                   return NULL;
1685                }
1686
1687              free_tmp = 1;
1688
1689              if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1690                {
1691                   free(tmp_data);
1692                   free(data);
1693                   return NULL;
1694                }
1695           }
1696
1697         if (efn->ciphered && cipher_key)
1698           {
1699             if (eet_decipher(tmp_data, compr_size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
1700               {
1701                 free(data);
1702                 if (free_tmp) free(tmp_data);
1703                 if (data_deciphered) free(data_deciphered);
1704                 return NULL;
1705               }
1706             free(tmp_data);
1707             tmp_data = data_deciphered;
1708             compr_size = data_deciphered_sz;
1709           }
1710
1711         /* decompress it */
1712         dlen = size;
1713         if (uncompress((Bytef *)data, &dlen,
1714                  tmp_data, (uLongf)compr_size))
1715           {
1716              free(data);
1717              return NULL;
1718           }
1719
1720         if (free_tmp)
1721           free(tmp_data);
1722      }
1723
1724    /* fill in return values */
1725    if (size_ret)
1726      *size_ret = size;
1727
1728    return data;
1729 }
1730
1731 EAPI void *
1732 eet_read(Eet_File *ef, const char *name, int *size_ret)
1733 {
1734    return eet_read_cipher(ef, name, size_ret, NULL);
1735 }
1736
1737 EAPI const void *
1738 eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
1739 {
1740    const void   *data = NULL;
1741    int           size = 0;
1742    Eet_File_Node *efn;
1743
1744    if (size_ret)
1745      *size_ret = 0;
1746
1747    /* check to see its' an eet file pointer */
1748    if (eet_check_pointer(ef))
1749      return NULL;
1750    if (!name)
1751      return NULL;
1752    if ((ef->mode != EET_FILE_MODE_READ) &&
1753        (ef->mode != EET_FILE_MODE_READ_WRITE))
1754      return NULL;
1755
1756    /* no header, return NULL */
1757    if (eet_check_header(ef))
1758      return NULL;
1759
1760    /* hunt hash bucket */
1761    efn = find_node_by_name(ef, name);
1762    if (!efn)
1763      return NULL;
1764
1765    if (efn->offset < 0 && efn->data == NULL)
1766      return NULL;
1767
1768    /* get size (uncompressed, if compressed at all) */
1769    size = efn->data_size;
1770
1771    /* uncompressed data */
1772    if (efn->compression == 0
1773        && efn->ciphered == 0)
1774      data = efn->data ? efn->data : ef->data + efn->offset;
1775    /* compressed data */
1776    else
1777      data = NULL;
1778
1779    /* fill in return values */
1780    if (size_ret)
1781      *size_ret = size;
1782
1783    return data;
1784 }
1785
1786 EAPI int
1787 eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int compress, const char *cipher_key)
1788 {
1789    Eet_File_Node        *efn;
1790    void                 *data2 = NULL;
1791    int                  exists_already = 0;
1792    int                  data_size;
1793    int                  hash;
1794
1795    /* check to see its' an eet file pointer */
1796    if (eet_check_pointer(ef))
1797      return 0;
1798    if ((!name) || (!data) || (size <= 0))
1799      return 0;
1800    if ((ef->mode != EET_FILE_MODE_WRITE) &&
1801        (ef->mode != EET_FILE_MODE_READ_WRITE))
1802      return 0;
1803
1804    if (!ef->header)
1805      {
1806         /* allocate header */
1807         ef->header = calloc(1, sizeof(Eet_File_Header));
1808         if (!ef->header)
1809           return 0;
1810
1811         ef->header->magic = EET_MAGIC_FILE_HEADER;
1812         /* allocate directory block in ram */
1813         ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1814         if (!ef->header->directory)
1815           return 0;
1816
1817         /* 8 bit hash table (256 buckets) */
1818         ef->header->directory->size = 8;
1819         /* allocate base hash table */
1820         ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1821         if (!ef->header->directory->nodes)
1822           return 0;
1823      }
1824
1825    /* figure hash bucket */
1826    hash = _eet_hash_gen(name, ef->header->directory->size);
1827
1828    data_size = compress ? 12 + ((size * 101) / 100) : size;
1829
1830    if (compress || !cipher_key)
1831      {
1832        data2 = malloc(data_size);
1833        if (!data2)
1834          return 0;
1835      }
1836
1837    /* if we want to compress */
1838    if (compress)
1839      {
1840         uLongf buflen;
1841
1842         /* compress the data with max compression */
1843         buflen = (uLongf)data_size;
1844         if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
1845                            (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
1846           {
1847              free(data2);
1848              return 0;
1849           }
1850         /* record compressed chunk size */
1851         data_size = (int)buflen;
1852         if (data_size < 0 || data_size >= size)
1853           {
1854              compress = 0;
1855              data_size = size;
1856           }
1857         else
1858           {
1859              void *data3;
1860
1861              data3 = realloc(data2, data_size);
1862              if (data3)
1863                data2 = data3;
1864           }
1865      }
1866
1867    if (cipher_key)
1868      {
1869        void *data_ciphered = NULL;
1870        unsigned int data_ciphered_sz = 0;
1871        const void *tmp;
1872
1873        tmp = data2 ? data2 : data;
1874        if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key), &data_ciphered, &data_ciphered_sz))
1875          {
1876            if (data2) free(data2);
1877            data2 = data_ciphered;
1878            data_size = data_ciphered_sz;
1879            size = (data_size > size) ? data_size : size;
1880          }
1881        else
1882          {
1883            if (data_ciphered) free(data_ciphered);
1884            cipher_key = NULL;
1885          }
1886      }
1887    else
1888      if (!compress)
1889        memcpy(data2, data, size);
1890
1891    /* Does this node already exist? */
1892    for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
1893      {
1894         /* if it matches */
1895         if ((efn->name) && (eet_string_match(efn->name, name)))
1896           {
1897              free(efn->data);
1898              efn->ciphered = cipher_key ? 1 : 0;
1899              efn->compression = !!compress;
1900              efn->size = data_size;
1901              efn->data_size = size;
1902              efn->data = data2;
1903              efn->offset = -1;
1904              exists_already = 1;
1905              break;
1906           }
1907      }
1908    if (!exists_already)
1909      {
1910         efn = malloc(sizeof(Eet_File_Node));
1911         if (!efn)
1912           {
1913              free(data2);
1914              return 0;
1915           }
1916         efn->name = strdup(name);
1917         efn->name_size = strlen(efn->name) + 1;
1918         efn->free_name = 1;
1919
1920         efn->next = ef->header->directory->nodes[hash];
1921         ef->header->directory->nodes[hash] = efn;
1922         efn->offset = -1;
1923         efn->ciphered = cipher_key ? 1 : 0;
1924         efn->compression = !!compress;
1925         efn->size = data_size;
1926         efn->data_size = size;
1927         efn->data = data2;
1928      }
1929
1930    /* flags that writes are pending */
1931    ef->writes_pending = 1;
1932    return data_size;
1933 }
1934
1935 EAPI int
1936 eet_write(Eet_File *ef, const char *name, const void *data, int size, int compress)
1937 {
1938    return eet_write_cipher(ef, name, data, size, compress, NULL);
1939 }
1940
1941 EAPI int
1942 eet_delete(Eet_File *ef, const char *name)
1943 {
1944    Eet_File_Node        *efn;
1945    Eet_File_Node        *pefn;
1946    int                  hash;
1947    int                  exists_already = 0;
1948
1949    /* check to see its' an eet file pointer */
1950    if (eet_check_pointer(ef))
1951      return 0;
1952    if (!name)
1953      return 0;
1954
1955    /* deleting keys is only possible in RW or WRITE mode */
1956    if (ef->mode == EET_FILE_MODE_READ)
1957      return 0;
1958
1959    if (eet_check_header(ef))
1960      return 0;
1961
1962    /* figure hash bucket */
1963    hash = _eet_hash_gen(name, ef->header->directory->size);
1964
1965    /* Does this node already exist? */
1966    for (pefn = NULL, efn = ef->header->directory->nodes[hash];
1967         efn;
1968         pefn = efn, efn = efn->next)
1969      {
1970         /* if it matches */
1971         if (eet_string_match(efn->name, name))
1972           {
1973              if (efn->data)
1974                free(efn->data);
1975
1976              if (pefn == NULL)
1977                ef->header->directory->nodes[hash] = efn->next;
1978              else
1979                pefn->next = efn->next;
1980
1981              if (efn->free_name) free(efn->name);
1982              free(efn);
1983              exists_already = 1;
1984              break;
1985           }
1986      }
1987    /* flags that writes are pending */
1988    if (exists_already)
1989      ef->writes_pending = 1;
1990
1991    /* update access time */
1992    return exists_already;
1993 }
1994
1995 EAPI Eet_Dictionary *
1996 eet_dictionary_get(Eet_File *ef)
1997 {
1998    if (eet_check_pointer(ef)) return NULL;
1999
2000    return ef->ed;
2001 }
2002
2003
2004 EAPI char **
2005 eet_list(Eet_File *ef, const char *glob, int *count_ret)
2006 {
2007    Eet_File_Node        *efn;
2008    char                 **list_ret = NULL;
2009    int                  list_count = 0;
2010    int                  list_count_alloc = 0;
2011    int                  i, num;
2012
2013    /* check to see its' an eet file pointer */
2014    if (eet_check_pointer(ef) || eet_check_header(ef) ||
2015        (!glob) ||
2016        ((ef->mode != EET_FILE_MODE_READ) &&
2017         (ef->mode != EET_FILE_MODE_READ_WRITE)))
2018      {
2019         if (count_ret)
2020           *count_ret = 0;
2021
2022         return NULL;
2023      }
2024
2025    /* loop through all entries */
2026    num = (1 << ef->header->directory->size);
2027    for (i = 0; i < num; i++)
2028      {
2029         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2030           {
2031              /* if the entry matches the input glob
2032               * check for * explicitly, because on some systems, * isn't well
2033               * supported
2034               */
2035              if ((!strcmp (glob, "*")) || !fnmatch(glob, efn->name, 0))
2036                {
2037                   /* add it to our list */
2038                   list_count++;
2039
2040                   /* only realloc in 32 entry chunks */
2041                   if (list_count > list_count_alloc)
2042                     {
2043                        char     **new_list = NULL;
2044
2045                        list_count_alloc += 64;
2046                        new_list = realloc(list_ret, list_count_alloc * (sizeof(char *)));
2047                        if (!new_list)
2048                          {
2049                             free(list_ret);
2050
2051                             if (count_ret)
2052                               *count_ret = 0;
2053
2054                             return NULL;
2055                          }
2056                        list_ret = new_list;
2057                     }
2058
2059                   /* put pointer of name string in */
2060                   list_ret[list_count - 1] = efn->name;
2061                }
2062           }
2063      }
2064
2065    /* return count and list */
2066    if (count_ret)
2067      *count_ret = list_count;
2068
2069    return list_ret;
2070 }
2071
2072 EAPI int
2073 eet_num_entries(Eet_File *ef)
2074 {
2075    int i, num, ret = 0;
2076    Eet_File_Node *efn;
2077
2078    /* check to see its' an eet file pointer */
2079    if (eet_check_pointer(ef) || eet_check_header(ef) ||
2080        ((ef->mode != EET_FILE_MODE_READ) &&
2081         (ef->mode != EET_FILE_MODE_READ_WRITE)))
2082      return -1;
2083
2084    /* loop through all entries */
2085    num = (1 << ef->header->directory->size);
2086    for (i = 0; i < num; i++)
2087      {
2088         for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2089           ret++;
2090      }
2091
2092    return ret;
2093 }
2094
2095 static Eet_File_Node *
2096 find_node_by_name(Eet_File *ef, const char *name)
2097 {
2098    Eet_File_Node *efn;
2099    int hash;
2100
2101    /* get hash bucket this should be in */
2102    hash = _eet_hash_gen(name, ef->header->directory->size);
2103
2104    for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2105      {
2106         if (eet_string_match(efn->name, name))
2107           return efn;
2108      }
2109
2110    return NULL;
2111 }
2112
2113 static int
2114 read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len)
2115 {
2116    if (efn->offset < 0) return 0;
2117
2118    if (ef->data)
2119      {
2120         if ((efn->offset + len) > ef->data_size) return 0;
2121         memcpy(buf, ef->data + efn->offset, len);
2122      }
2123    else
2124      {
2125         /* seek to data location */
2126         if (fseek(ef->fp, efn->offset, SEEK_SET) < 0)
2127           return 0;
2128
2129         /* read it */
2130         len = fread(buf, len, 1, ef->fp);
2131      }
2132    return len;
2133 }