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