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