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