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