3 #endif /* ifdef HAVE_CONFIG_H */
8 # define alloca __builtin_alloca
10 # define alloca __alloca
11 #elif defined _MSC_VER
13 # define alloca _alloca
14 #else /* ifdef HAVE_ALLOCA_H */
18 # endif /* ifdef __cplusplus */
20 #endif /* ifdef HAVE_ALLOCA_H */
23 # include <winsock2.h>
24 #endif /* ifdef _WIN32 */
28 #include <sys/types.h>
38 #endif /* ifdef HAVE_UNISTD_H */
40 #ifdef HAVE_NETINET_IN_H
41 # include <netinet/in.h>
42 #endif /* ifdef HAVE_NETINET_IN_H */
46 #endif /* ifdef HAVE_EVIL */
51 # include <gnutls/gnutls.h>
53 #endif /* ifdef HAVE_GNUTLS */
56 # include <openssl/err.h>
57 # include <openssl/evp.h>
58 #endif /* ifdef HAVE_OPENSSL */
60 #ifdef EINA_HAVE_THREADS
62 GCRY_THREAD_OPTION_PTHREAD_IMPL;
63 # endif /* ifdef HAVE_GNUTLS */
64 #endif /* ifdef EINA_HAVE_THREADS */
67 #include "Eet_private.h"
73 static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
74 EAPI Eet_Version *eet_version = &_version;
78 #endif /* ifdef HAVE_REALPATH */
80 #define EET_MAGIC_FILE 0x1ee7ff00
81 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
83 #define EET_MAGIC_FILE2 0x1ee70f42
85 #define EET_FILE2_HEADER_COUNT 3
86 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
87 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
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)
96 /* prototypes of internal calls */
98 eet_cache_find(const char *path,
102 eet_cache_add(Eet_File *ef,
107 eet_cache_del(Eet_File *ef,
112 eet_string_match(const char *s1,
116 eet_flush(Eet_File *ef);
119 eet_flush2(Eet_File *ef);
120 static Eet_File_Node *
121 find_node_by_name(Eet_File *ef,
124 read_data_from_disk(Eet_File *ef,
130 eet_internal_close(Eet_File *ef,
133 static Eina_Lock eet_cache_lock;
135 #define LOCK_CACHE eina_lock_take(&eet_cache_lock)
136 #define UNLOCK_CACHE eina_lock_release(&eet_cache_lock)
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)
143 /* cache. i don't expect this to ever be large, so arrays will do */
144 static int eet_writers_num = 0;
145 static int eet_writers_alloc = 0;
146 static Eet_File **eet_writers = NULL;
147 static int eet_readers_num = 0;
148 static int eet_readers_alloc = 0;
149 static Eet_File **eet_readers = NULL;
150 static int eet_init_count = 0;
152 /* log domain variable */
153 int _eet_log_dom_global = -1;
155 /* Check to see its' an eet file pointer */
157 eet_check_pointer(const Eet_File *ef)
159 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
166 eet_check_header(const Eet_File *ef)
171 if (!ef->header->directory)
178 eet_test_close(int test,
183 ef->delete_me_now = 1;
184 eet_internal_close(ef, EINA_TRUE);
190 /* find an eet file in the currently in use cache */
192 eet_cache_find(const char *path,
199 for (i = 0; i < cache_num; i++)
201 /* if matches real path - return it */
202 if (eet_string_match(cache[i]->path, path))
203 if (!cache[i]->delete_me_now)
211 /* add to end of cache */
212 /* this should only be called when the cache lock is already held */
214 eet_cache_add(Eet_File *ef,
219 Eet_File **new_cache;
223 new_cache_num = *cache_num;
224 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
226 Eet_File *del_ef = NULL;
230 for (i = 0; i < new_cache_num; i++)
232 if (new_cache[i]->references == 0)
234 del_ef = new_cache[i];
241 del_ef->delete_me_now = 1;
242 eet_internal_close(del_ef, EINA_TRUE);
247 new_cache_num = *cache_num;
248 new_cache_alloc = *cache_alloc;
250 if (new_cache_num > new_cache_alloc)
252 new_cache_alloc += 16;
253 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
256 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
261 new_cache[new_cache_num - 1] = ef;
263 *cache_num = new_cache_num;
264 *cache_alloc = new_cache_alloc;
267 /* delete from cache */
268 /* this should only be called when the cache lock is already held */
270 eet_cache_del(Eet_File *ef,
275 Eet_File **new_cache;
276 int new_cache_num, new_cache_alloc;
280 new_cache_num = *cache_num;
281 new_cache_alloc = *cache_alloc;
282 if (new_cache_num <= 0)
285 for (i = 0; i < new_cache_num; i++)
287 if (new_cache[i] == ef)
291 if (i >= new_cache_num)
295 for (j = i; j < new_cache_num; j++)
296 new_cache[j] = new_cache[j + 1];
298 if (new_cache_num <= (new_cache_alloc - 16))
300 new_cache_alloc -= 16;
301 if (new_cache_num > 0)
303 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
306 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
318 *cache_num = new_cache_num;
319 *cache_alloc = new_cache_alloc;
322 /* internal string match. null friendly, catches same ptr */
324 eet_string_match(const char *s1,
327 /* both null- no match */
334 return !strcmp(s1, s2);
337 /* flush out writes to a v2 eet file */
339 eet_flush2(Eet_File *ef)
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;
351 int strings_offset = 0;
356 if (eet_check_pointer(ef))
357 return EET_ERROR_BAD_OBJECT;
359 if (eet_check_header(ef))
360 return EET_ERROR_EMPTY;
362 if (!ef->writes_pending)
363 return EET_ERROR_NONE;
365 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
366 || (ef->mode == EET_FILE_MODE_WRITE))
370 /* opening for write - delete old copy of file right away */
372 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
373 fp = fdopen(fd, "wb");
375 return EET_ERROR_NOT_WRITABLE;
377 fcntl(fd, F_SETFD, FD_CLOEXEC);
380 return EET_ERROR_NOT_WRITABLE;
382 /* calculate string base offset and data base offset */
383 num = (1 << ef->header->directory->size);
384 for (i = 0; i < num; ++i)
386 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
388 num_directory_entries++;
389 bytes_strings += strlen(efn->name) + 1;
394 num_dictionary_entries = ef->ed->count;
396 for (i = 0; i < num_dictionary_entries; ++i)
397 bytes_strings += ef->ed->all[i].len;
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;
406 /* calculate per entry offset */
407 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
408 data_offset = bytes_directory_entries + bytes_dictionary_entries +
411 for (i = 0; i < num; ++i)
413 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
415 efn->offset = data_offset;
416 data_offset += efn->size;
418 efn->name_offset = strings_offset;
419 strings_offset += efn->name_size;
423 /* calculate dictionary strings offset */
425 ef->ed->offset = strings_offset;
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);
432 fseek(fp, 0, SEEK_SET);
433 if (fwrite(head, sizeof (head), 1, fp) != 1)
436 /* write directories entry */
437 for (i = 0; i < num; i++)
439 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
442 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
444 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
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);
453 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
458 /* write dictionary */
461 int offset = strings_offset;
463 for (j = 0; j < ef->ed->count; ++j)
465 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
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);
473 offset += ef->ed->all[j].len;
475 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
480 /* write directories name */
481 for (i = 0; i < num; i++)
483 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
485 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
492 for (j = 0; j < ef->ed->count; ++j)
494 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
499 for (i = 0; i < num; i++)
501 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
503 if (fwrite(efn->data, efn->size, 1, fp) != 1)
508 /* flush all write to the file. */
511 /* append signature if required */
514 error = eet_identity_sign(fp, ef->key);
515 if (error != EET_ERROR_NONE)
519 /* no more writes pending */
520 ef->writes_pending = 0;
524 return EET_ERROR_NONE;
531 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
533 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
535 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
537 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
539 default: error = EET_ERROR_WRITE_ERROR; break;
551 if (++eet_init_count != 1)
552 return eet_init_count;
555 return --eet_init_count;
557 _eet_log_dom_global = eina_log_domain_register("eet", EET_DEFAULT_LOG_COLOR);
558 if (_eet_log_dom_global < 0)
560 EINA_LOG_ERR("Eet Can not create a general log domain.");
564 eina_lock_new(&eet_cache_lock);
566 if (!eet_mempool_init())
568 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
569 goto unregister_log_domain;
572 if (!eet_node_init())
574 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
575 goto shutdown_mempool;
579 /* Before the library can be used, it must initialize itself if needed. */
580 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
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. */
593 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
595 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
598 # ifdef EINA_HAVE_THREADS
599 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
601 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
603 # endif /* ifdef EINA_HAVE_THREADS */
604 if (gnutls_global_init())
607 #endif /* ifdef HAVE_GNUTLS */
609 ERR_load_crypto_strings();
610 OpenSSL_add_all_algorithms();
611 #endif /* ifdef HAVE_OPENSSL */
613 return eet_init_count;
620 eet_mempool_shutdown();
621 unregister_log_domain:
622 eina_log_domain_unregister(_eet_log_dom_global);
623 _eet_log_dom_global = -1;
626 return --eet_init_count;
632 if (--eet_init_count != 0)
633 return eet_init_count;
637 eet_mempool_shutdown();
639 eina_lock_free(&eet_cache_lock);
642 gnutls_global_deinit();
643 #endif /* ifdef HAVE_GNUTLS */
647 #endif /* ifdef HAVE_OPENSSL */
648 eina_log_domain_unregister(_eet_log_dom_global);
649 _eet_log_dom_global = -1;
652 return eet_init_count;
656 eet_sync(Eet_File *ef)
660 if (eet_check_pointer(ef))
661 return EET_ERROR_BAD_OBJECT;
663 if ((ef->mode != EET_FILE_MODE_WRITE) &&
664 (ef->mode != EET_FILE_MODE_READ_WRITE))
665 return EET_ERROR_NOT_WRITABLE;
667 if (!ef->writes_pending)
668 return EET_ERROR_NONE;
672 ret = eet_flush2(ef);
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.
689 for (i = 0; i < eet_writers_num; i++)
691 if (eet_writers[i]->references <= 0)
695 for (i = 0; i < eet_readers_num; i++)
697 if (eet_readers[i]->references <= 0)
703 Eet_File **closelist = NULL;
705 closelist = alloca(num * sizeof(Eet_File *));
707 for (i = 0; i < eet_writers_num; i++)
709 if (eet_writers[i]->references <= 0)
711 closelist[num] = eet_writers[i];
712 eet_writers[i]->delete_me_now = 1;
717 for (i = 0; i < eet_readers_num; i++)
719 if (eet_readers[i]->references <= 0)
721 closelist[num] = eet_readers[i];
722 eet_readers[i]->delete_me_now = 1;
727 for (i = 0; i < num; i++)
729 eet_internal_close(closelist[i], EINA_TRUE);
736 /* FIXME: MMAP race condition in READ_WRITE_MODE */
738 eet_internal_read2(Eet_File *ef)
740 const int *data = (const int *)ef->data;
741 const char *start = (const char *)ef->data;
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;
751 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
756 #define GET_INT(Value, Pointer, Index) \
758 Value = ntohl(*Pointer); \
760 Index += sizeof(int); \
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);
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;
773 /* we can't have > 0x7fffffff values here - invalid */
774 if (eet_test_close((num_directory_entries > 0x7fffffff), ef))
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) >
782 /* allocate header */
783 ef->header = eet_file_header_calloc(1);
784 if (eet_test_close(!ef->header, ef))
787 ef->header->magic = EET_MAGIC_FILE_HEADER;
789 /* allocate directory block in ram */
790 ef->header->directory = eet_file_directory_calloc(1);
791 if (eet_test_close(!ef->header->directory, ef))
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))
802 signature_base_offset = 0;
803 if (num_directory_entries == 0)
805 signature_base_offset = ef->data_size;
808 /* actually read the directory block - all of it, into ram */
809 for (i = 0; i < num_directory_entries; ++i)
813 unsigned long int name_offset;
814 unsigned long int name_size;
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))
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 */
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);
837 efn->compression = flag & 0x1 ? 1 : 0;
838 efn->ciphered = flag & 0x2 ? 1 : 0;
839 efn->alias = flag & 0x4 ? 1 : 0;
841 #define EFN_TEST(Test, Ef, Efn) \
842 if (eet_test_close(Test, Ef)) \
844 eet_file_node_mp_free(Efn); \
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);
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);
860 name = start + name_offset;
862 /* check '\0' at the end of name string */
863 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
866 efn->name = (char *)name;
867 efn->name_size = name_size;
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;
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 */
878 efn->data = malloc(efn->size);
880 memcpy(efn->data, ef->data + efn->offset, efn->size);
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;
890 if (num_dictionary_entries)
892 const int *dico = (const int *)ef->data +
893 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
894 EET_FILE2_HEADER_COUNT;
897 if (eet_test_close((num_dictionary_entries *
898 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
899 (bytes_dictionary_entries + bytes_directory_entries),
903 ef->ed = eet_dictionary_calloc(1);
904 if (eet_test_close(!ef->ed, ef))
907 ef->ed->all = calloc(1, num_dictionary_entries * sizeof(Eet_String));
908 if (eet_test_close(!ef->ed->all, ef))
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;
917 for (j = 0; j < ef->ed->count; ++j)
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);
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))
933 /* Check string position */
934 if (eet_test_close(!((ef->ed->all[j].len > 0)
936 (bytes_dictionary_entries +
937 bytes_directory_entries))
938 && (offset + ef->ed->all[j].len <
939 ef->data_size)), ef))
942 ef->ed->all[j].str = start + offset;
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;
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] !=
952 ef->ed->all[j].hash = hash;
953 if (ef->ed->all[j].prev == -1)
954 ef->ed->hash[hash] = j;
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;
962 /* Check if the file is signed */
965 ef->signature = NULL;
966 ef->signature_length = 0;
968 if (signature_base_offset < ef->data_size)
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,
978 ef->data_size - signature_base_offset,
980 &ef->signature_length,
983 if (eet_test_close(!ef->x509_der, ef))
986 #else /* ifdef HAVE_SIGNATURE */
988 "This file could be signed but you didn't compile the necessary code to check the signature.");
989 #endif /* ifdef HAVE_SIGNATURE */
995 #if EET_OLD_EET_FILE_FORMAT
997 eet_internal_read1(Eet_File *ef)
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;
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.",
1010 /* build header table if read mode */
1013 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1016 #define EXTRACT_INT(Value, Pointer, Index) \
1019 memcpy(&tmp, Pointer + Index, sizeof(int)); \
1020 Value = ntohl(tmp); \
1021 Index += sizeof(int); \
1024 /* get entries count and byte count */
1025 EXTRACT_INT(num_entries, ef->data, idx);
1026 EXTRACT_INT(byte_entries, ef->data, idx);
1028 /* we can't have <= 0 values here - invalid */
1029 if (eet_test_close((num_entries > 0x7fffffff) ||
1030 (byte_entries > 0x7fffffff), ef))
1033 /* we can't have more entires than minimum bytes for those! invalid! */
1034 if (eet_test_close((num_entries * 20) > byte_entries, ef))
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))
1042 /* allocate header */
1043 ef->header = eet_file_header_calloc(1);
1044 if (eet_test_close(!ef->header, ef))
1047 ef->header->magic = EET_MAGIC_FILE_HEADER;
1049 /* allocate directory block in ram */
1050 ef->header->directory = eet_file_directory_calloc(1);
1051 if (eet_test_close(!ef->header->directory, ef))
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))
1062 /* actually read the directory block - all of it, into ram */
1063 dyn_buf = ef->data + idx;
1065 /* parse directory block */
1068 for (i = 0; i < num_entries; i++)
1077 #define HEADER_SIZE (sizeof(int) * 5)
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))
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))
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 */
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);
1101 efn->name_size = name_size;
1106 if (eet_test_close(efn->size <= 0, ef))
1108 eet_file_node_mp_free(efn);
1112 /* invalid name_size */
1113 if (eet_test_close(name_size <= 0, ef))
1115 eet_file_node_mp_free(efn);
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))
1122 eet_file_node_mp_free(efn);
1126 /* This code is useless if we dont want backward compatibility */
1128 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1131 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1135 efn->name = malloc(sizeof(char) * name_size + 1);
1136 if (eet_test_close(!efn->name, ef))
1138 eet_file_node_mp_free(efn);
1142 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1143 efn->name[name_size] = 0;
1146 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1151 /* The only really useful peace of code for efn->name (no backward compatibility) */
1152 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
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;
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 */
1164 data = malloc(efn->size);
1166 memcpy(data, ef->data + efn->offset, efn->size);
1172 p += HEADER_SIZE + name_size;
1177 #endif /* if EET_OLD_EET_FILE_FORMAT */
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.)
1186 eet_internal_read(Eet_File *ef)
1188 const int *data = (const int *)ef->data;
1190 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1193 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1196 switch (ntohl(*data))
1198 #if EET_OLD_EET_FILE_FORMAT
1199 case EET_MAGIC_FILE:
1200 return eet_internal_read1(ef);
1202 #endif /* if EET_OLD_EET_FILE_FORMAT */
1203 case EET_MAGIC_FILE2:
1204 return eet_internal_read2(ef);
1207 ef->delete_me_now = 1;
1208 eet_internal_close(ef, EINA_TRUE);
1216 eet_internal_close(Eet_File *ef,
1221 /* check to see its' an eet file pointer */
1222 if (eet_check_pointer(ef))
1223 return EET_ERROR_BAD_OBJECT;
1230 /* if its still referenced - dont go any further */
1231 if (ef->references > 0)
1233 /* flush any writes */
1234 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1235 (ef->mode == EET_FILE_MODE_READ_WRITE))
1240 err = eet_flush2(ef);
1242 eet_identity_unref(ef->key);
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))
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);
1256 /* we can unlock the cache now */
1265 if (ef->header->directory)
1267 if (ef->header->directory->nodes)
1271 num = (1 << ef->header->directory->size);
1272 for (i = 0; i < num; i++)
1276 while ((efn = ef->header->directory->nodes[i]))
1281 ef->header->directory->nodes[i] = efn->next;
1286 eet_file_node_mp_free(efn);
1289 free(ef->header->directory->nodes);
1292 eet_file_directory_mp_free(ef->header->directory);
1295 eet_file_header_mp_free(ef->header);
1298 eet_dictionary_free(ef->ed);
1306 eina_file_map_free(ef->readfp, (void *)ef->data);
1308 eina_file_close(ef->readfp);
1311 /* zero out ram for struct - caution tactic against stale memory use */
1312 memset(ef, 0, sizeof(Eet_File));
1315 eina_stringshare_del(ef->path);
1316 eet_file_mp_free(ef);
1323 return EET_ERROR_NONE;
1327 eet_memopen_read(const void *data,
1332 if (!data || size == 0)
1335 ef = eet_file_malloc(1);
1343 ef->magic = EET_MAGIC_FILE;
1345 ef->mode = EET_FILE_MODE_READ;
1347 ef->delete_me_now = 1;
1350 ef->data_size = size;
1352 ef->sha1_length = 0;
1354 /* eet_internal_read expects the cache lock to be held when it is called */
1356 ef = eet_internal_read(ef);
1362 eet_file_get(Eet_File *ef)
1364 if (eet_check_pointer(ef)) return NULL;
1369 eet_open(const char *file,
1375 unsigned long int size;
1380 /* find the current file handle in cache*/
1383 if (mode == EET_FILE_MODE_READ)
1385 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1390 ef->delete_me_now = 1;
1391 eet_internal_close(ef, EINA_TRUE);
1394 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1396 else if ((mode == EET_FILE_MODE_WRITE) ||
1397 (mode == EET_FILE_MODE_READ_WRITE))
1399 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1402 ef->delete_me_now = 1;
1404 eet_internal_close(ef, EINA_TRUE);
1407 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1410 /* try open the file based on mode */
1411 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1413 /* Prevent garbage in futur comparison. */
1414 fp = eina_file_open(file, EINA_FALSE);
1421 size = eina_file_size_get(fp);
1423 if (size < ((int)sizeof(int) * 3))
1425 eina_file_close(fp);
1434 if (!fp && mode == EET_FILE_MODE_READ)
1439 if (mode != EET_FILE_MODE_WRITE)
1448 if (ef && ef->readfp != fp)
1450 ef->delete_me_now = 1;
1452 eet_internal_close(ef, EINA_TRUE);
1458 /* reference it up and return it */
1460 eina_file_close(fp);
1467 file_len = strlen(file) + 1;
1469 /* Allocate struct for eet file and have it zero'd out */
1470 ef = eet_file_malloc(1);
1474 /* fill some of the members */
1478 ef->path = eina_stringshare_add_length(file, file_len);
1479 ef->magic = EET_MAGIC_FILE;
1483 ef->writes_pending = 0;
1484 ef->delete_me_now = 0;
1488 ef->sha1_length = 0;
1490 ef->ed = (mode == EET_FILE_MODE_WRITE)
1491 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1492 eet_dictionary_add() : NULL;
1495 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1498 /* if we can't open - bail out */
1499 if (eet_test_close(!ef->readfp, ef))
1502 /* if we opened for read or read-write */
1503 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1505 ef->data_size = size;
1506 ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL);
1507 if (eet_test_close((ef->data == NULL), ef))
1510 ef = eet_internal_read(ef);
1517 if (ef->references == 1)
1519 if (ef->mode == EET_FILE_MODE_READ)
1520 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1521 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1522 (ef->mode == EET_FILE_MODE_READ_WRITE))
1523 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1535 eet_mode_get(Eet_File *ef)
1537 /* check to see its' an eet file pointer */
1538 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1539 return EET_FILE_MODE_INVALID;
1545 eet_identity_x509(Eet_File *ef,
1552 *der_length = ef->x509_length;
1554 return ef->x509_der;
1558 eet_identity_signature(Eet_File *ef,
1559 int *signature_length)
1564 if (signature_length)
1565 *signature_length = ef->signature_length;
1567 return ef->signature;
1571 eet_identity_sha1(Eet_File *ef,
1575 ef->sha1 = eet_identity_compute_sha1(ef->data,
1580 *sha1_length = ef->sha1_length;
1586 eet_identity_set(Eet_File *ef,
1592 return EET_ERROR_BAD_OBJECT;
1596 eet_identity_ref(ef->key);
1597 eet_identity_unref(tmp);
1599 /* flags that writes are pending */
1600 ef->writes_pending = 1;
1602 return EET_ERROR_NONE;
1606 eet_close(Eet_File *ef)
1608 return eet_internal_close(ef, EINA_FALSE);
1612 eet_read_cipher(Eet_File *ef,
1615 const char *cipher_key)
1619 unsigned long int size = 0;
1624 /* check to see its' an eet file pointer */
1625 if (eet_check_pointer(ef))
1631 if ((ef->mode != EET_FILE_MODE_READ) &&
1632 (ef->mode != EET_FILE_MODE_READ_WRITE))
1635 /* no header, return NULL */
1636 if (eet_check_header(ef))
1641 /* hunt hash bucket */
1642 efn = find_node_by_name(ef, name);
1646 /* get size (uncompressed, if compressed at all) */
1647 size = efn->data_size;
1650 data = malloc(size);
1654 /* uncompressed data */
1655 if (efn->compression == 0)
1657 void *data_deciphered = NULL;
1658 unsigned int data_deciphered_sz = 0;
1659 /* if we already have the data in ram... copy that */
1661 if (efn->ciphered && efn->size > size)
1664 data = realloc(data, efn->size);
1668 memcpy(data, efn->data, size);
1670 if (!read_data_from_disk(ef, efn, data, size))
1673 if (efn->ciphered && cipher_key)
1675 if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key),
1676 &data_deciphered, &data_deciphered_sz))
1678 if (data_deciphered)
1679 free(data_deciphered);
1685 data = data_deciphered;
1686 size = data_deciphered_sz;
1689 /* compressed data */
1692 void *tmp_data = NULL;
1693 void *data_deciphered = NULL;
1694 unsigned int data_deciphered_sz = 0;
1696 int compr_size = efn->size;
1699 /* if we already have the data in ram... copy that */
1701 tmp_data = efn->data;
1704 tmp_data = malloc(compr_size);
1710 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1717 if (efn->ciphered && cipher_key)
1719 if (eet_decipher(tmp_data, compr_size, cipher_key,
1720 strlen(cipher_key), &data_deciphered,
1721 &data_deciphered_sz))
1726 if (data_deciphered)
1727 free(data_deciphered);
1735 tmp_data = data_deciphered;
1736 compr_size = data_deciphered_sz;
1741 if (uncompress((Bytef *)data, &dlen,
1742 tmp_data, (uLongf)compr_size))
1760 if (data[size - 1] != '\0')
1763 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1770 /* fill in return values */
1783 eet_read(Eet_File *ef,
1787 return eet_read_cipher(ef, name, size_ret, NULL);
1791 eet_read_direct(Eet_File *ef,
1796 const char *data = NULL;
1802 /* check to see its' an eet file pointer */
1803 if (eet_check_pointer(ef))
1809 if ((ef->mode != EET_FILE_MODE_READ) &&
1810 (ef->mode != EET_FILE_MODE_READ_WRITE))
1813 /* no header, return NULL */
1814 if (eet_check_header(ef))
1819 /* hunt hash bucket */
1820 efn = find_node_by_name(ef, name);
1824 /* trick to detect data in memory instead of mmaped from disk */
1825 if (efn->offset > ef->data_size && !efn->data)
1828 /* get size (uncompressed, if compressed at all) */
1829 size = efn->data_size;
1833 data = efn->data ? efn->data : ef->data + efn->offset;
1835 /* handle alias case */
1836 if (efn->compression)
1839 int compr_size = efn->size;
1842 tmp = alloca(sizeof (compr_size));
1845 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1846 (uLongf)compr_size))
1849 if (tmp[compr_size - 1] != '\0')
1854 return eet_read_direct(ef, tmp, size_ret);
1860 if (data[size - 1] != '\0')
1865 return eet_read_direct(ef, data, size_ret);
1868 /* uncompressed data */
1869 if (efn->compression == 0
1870 && efn->ciphered == 0)
1871 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1875 /* fill in return values */
1889 eet_alias_get(Eet_File *ef,
1893 const char *data = NULL;
1896 /* check to see its' an eet file pointer */
1897 if (eet_check_pointer(ef))
1903 if ((ef->mode != EET_FILE_MODE_READ) &&
1904 (ef->mode != EET_FILE_MODE_READ_WRITE))
1907 /* no header, return NULL */
1908 if (eet_check_header(ef))
1913 /* hunt hash bucket */
1914 efn = find_node_by_name(ef, name);
1918 /* trick to detect data in memory instead of mmaped from disk */
1919 if (efn->offset > ef->data_size && !efn->data)
1922 /* get size (uncompressed, if compressed at all) */
1923 size = efn->data_size;
1925 if (!efn->alias) return NULL;
1926 data = efn->data ? efn->data : ef->data + efn->offset;
1928 /* handle alias case */
1929 if (efn->compression)
1932 int compr_size = efn->size;
1935 tmp = alloca(sizeof (compr_size));
1938 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1939 (uLongf)compr_size))
1942 if (tmp[compr_size - 1] != '\0')
1947 return eina_stringshare_add(tmp);
1953 if (data[size - 1] != '\0')
1958 return eina_stringshare_add(data);
1966 eet_alias(Eet_File *ef,
1968 const char *destination,
1973 Eina_Bool exists_already = EINA_FALSE;
1977 /* check to see its' an eet file pointer */
1978 if (eet_check_pointer(ef))
1981 if ((!name) || (!destination))
1984 if ((ef->mode != EET_FILE_MODE_WRITE) &&
1985 (ef->mode != EET_FILE_MODE_READ_WRITE))
1992 /* allocate header */
1993 ef->header = eet_file_header_calloc(1);
1997 ef->header->magic = EET_MAGIC_FILE_HEADER;
1998 /* allocate directory block in ram */
1999 ef->header->directory = eet_file_directory_calloc(1);
2000 if (!ef->header->directory)
2002 eet_file_header_mp_free(ef->header);
2007 /* 8 bit hash table (256 buckets) */
2008 ef->header->directory->size = 8;
2009 /* allocate base hash table */
2010 ef->header->directory->nodes =
2011 calloc(1, sizeof(Eet_File_Node *) *
2012 (1 << ef->header->directory->size));
2013 if (!ef->header->directory->nodes)
2015 eet_file_directory_mp_free(ef->header->directory);
2021 /* figure hash bucket */
2022 hash = _eet_hash_gen(name, ef->header->directory->size);
2025 12 + (((strlen(destination) + 1) * 101) / 100)
2026 : strlen(destination) + 1;
2028 data2 = malloc(data_size);
2032 /* if we want to compress */
2037 /* compress the data with max compression */
2038 buflen = (uLongf)data_size;
2039 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2040 (uLong)strlen(destination) + 1,
2041 Z_BEST_COMPRESSION) != Z_OK)
2047 /* record compressed chunk size */
2048 data_size = (int)buflen;
2049 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2052 data_size = strlen(destination) + 1;
2058 data3 = realloc(data2, data_size);
2065 memcpy(data2, destination, data_size);
2067 /* Does this node already exist? */
2068 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2071 if ((efn->name) && (eet_string_match(efn->name, name)))
2076 efn->compression = !!comp;
2077 efn->size = data_size;
2078 efn->data_size = strlen(destination) + 1;
2080 /* Put the offset above the limit to avoid direct access */
2081 efn->offset = ef->data_size + 1;
2082 exists_already = EINA_TRUE;
2087 if (!exists_already)
2089 efn = eet_file_node_malloc(1);
2096 efn->name = strdup(name);
2097 efn->name_size = strlen(efn->name) + 1;
2100 efn->next = ef->header->directory->nodes[hash];
2101 ef->header->directory->nodes[hash] = efn;
2102 /* Put the offset above the limit to avoid direct access */
2103 efn->offset = ef->data_size + 1;
2106 efn->compression = !!comp;
2107 efn->size = data_size;
2108 efn->data_size = strlen(destination) + 1;
2112 /* flags that writes are pending */
2113 ef->writes_pending = 1;
2124 eet_write_cipher(Eet_File *ef,
2129 const char *cipher_key)
2133 int exists_already = 0;
2137 /* check to see its' an eet file pointer */
2138 if (eet_check_pointer(ef))
2141 if ((!name) || (!data) || (size <= 0))
2144 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2145 (ef->mode != EET_FILE_MODE_READ_WRITE))
2152 /* allocate header */
2153 ef->header = eet_file_header_calloc(1);
2157 ef->header->magic = EET_MAGIC_FILE_HEADER;
2158 /* allocate directory block in ram */
2159 ef->header->directory = eet_file_directory_calloc(1);
2160 if (!ef->header->directory)
2162 eet_file_header_mp_free(ef->header);
2167 /* 8 bit hash table (256 buckets) */
2168 ef->header->directory->size = 8;
2169 /* allocate base hash table */
2170 ef->header->directory->nodes =
2171 calloc(1, sizeof(Eet_File_Node *) *
2172 (1 << ef->header->directory->size));
2173 if (!ef->header->directory->nodes)
2175 eet_file_directory_mp_free(ef->header->directory);
2181 /* figure hash bucket */
2182 hash = _eet_hash_gen(name, ef->header->directory->size);
2184 data_size = comp ? 12 + ((size * 101) / 100) : size;
2186 if (comp || !cipher_key)
2188 data2 = malloc(data_size);
2193 /* if we want to compress */
2198 /* compress the data with max compression */
2199 buflen = (uLongf)data_size;
2200 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2201 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2207 /* record compressed chunk size */
2208 data_size = (int)buflen;
2209 if (data_size < 0 || data_size >= size)
2218 data3 = realloc(data2, data_size);
2226 void *data_ciphered = NULL;
2227 unsigned int data_ciphered_sz = 0;
2230 tmp = comp ? data2 : data;
2231 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2232 &data_ciphered, &data_ciphered_sz))
2237 data2 = data_ciphered;
2238 data_size = data_ciphered_sz;
2243 free(data_ciphered);
2250 memcpy(data2, data, size);
2252 /* Does this node already exist? */
2253 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2256 if ((efn->name) && (eet_string_match(efn->name, name)))
2260 efn->ciphered = cipher_key ? 1 : 0;
2261 efn->compression = !!comp;
2262 efn->size = data_size;
2263 efn->data_size = size;
2265 /* Put the offset above the limit to avoid direct access */
2266 efn->offset = ef->data_size + 1;
2271 if (!exists_already)
2273 efn = eet_file_node_malloc(1);
2280 efn->name = strdup(name);
2281 efn->name_size = strlen(efn->name) + 1;
2284 efn->next = ef->header->directory->nodes[hash];
2285 ef->header->directory->nodes[hash] = efn;
2286 /* Put the offset above the limit to avoid direct access */
2287 efn->offset = ef->data_size + 1;
2289 efn->ciphered = cipher_key ? 1 : 0;
2290 efn->compression = !!comp;
2291 efn->size = data_size;
2292 efn->data_size = size;
2296 /* flags that writes are pending */
2297 ef->writes_pending = 1;
2307 eet_write(Eet_File *ef,
2313 return eet_write_cipher(ef, name, data, size, comp, NULL);
2317 eet_delete(Eet_File *ef,
2321 Eet_File_Node *pefn;
2323 int exists_already = 0;
2325 /* check to see its' an eet file pointer */
2326 if (eet_check_pointer(ef))
2332 /* deleting keys is only possible in RW or WRITE mode */
2333 if (ef->mode == EET_FILE_MODE_READ)
2336 if (eet_check_header(ef))
2341 /* figure hash bucket */
2342 hash = _eet_hash_gen(name, ef->header->directory->size);
2344 /* Does this node already exist? */
2345 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2347 pefn = efn, efn = efn->next)
2350 if (eet_string_match(efn->name, name))
2356 ef->header->directory->nodes[hash] = efn->next;
2358 pefn->next = efn->next;
2363 eet_file_node_mp_free(efn);
2368 /* flags that writes are pending */
2370 ef->writes_pending = 1;
2374 /* update access time */
2375 return exists_already;
2378 EAPI Eet_Dictionary *
2379 eet_dictionary_get(Eet_File *ef)
2381 if (eet_check_pointer(ef))
2388 eet_list(Eet_File *ef,
2393 char **list_ret = NULL;
2395 int list_count_alloc = 0;
2398 /* check to see its' an eet file pointer */
2399 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2401 ((ef->mode != EET_FILE_MODE_READ) &&
2402 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2410 if (!strcmp(glob, "*"))
2415 /* loop through all entries */
2416 num = (1 << ef->header->directory->size);
2417 for (i = 0; i < num; i++)
2419 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2421 /* if the entry matches the input glob
2422 * check for * explicitly, because on some systems, * isn't well
2425 if ((!glob) || !fnmatch(glob, efn->name, 0))
2427 /* add it to our list */
2430 /* only realloc in 32 entry chunks */
2431 if (list_count > list_count_alloc)
2433 char **new_list = NULL;
2435 list_count_alloc += 64;
2437 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2445 list_ret = new_list;
2448 /* put pointer of name string in */
2449 list_ret[list_count - 1] = efn->name;
2456 /* return count and list */
2458 *count_ret = list_count;
2472 eet_num_entries(Eet_File *ef)
2474 int i, num, ret = 0;
2477 /* check to see its' an eet file pointer */
2478 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2479 ((ef->mode != EET_FILE_MODE_READ) &&
2480 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2485 /* loop through all entries */
2486 num = (1 << ef->header->directory->size);
2487 for (i = 0; i < num; i++)
2489 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2498 static Eet_File_Node *
2499 find_node_by_name(Eet_File *ef,
2505 /* get hash bucket this should be in */
2506 hash = _eet_hash_gen(name, ef->header->directory->size);
2508 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2510 if (eet_string_match(efn->name, name))
2518 read_data_from_disk(Eet_File *ef,
2523 if (efn->offset > ef->data_size)
2529 if ((efn->offset + len) > ef->data_size)
2532 memcpy(buf, ef->data + efn->offset, len);