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