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