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"
76 static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
77 EAPI Eet_Version *eet_version = &_version;
81 #endif /* ifdef HAVE_REALPATH */
83 #define EET_MAGIC_FILE 0x1ee7ff00
84 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
86 #define EET_MAGIC_FILE2 0x1ee70f42
88 #define EET_FILE2_HEADER_COUNT 3
89 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
90 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
92 #define EET_FILE2_HEADER_SIZE (sizeof(int) * \
93 EET_FILE2_HEADER_COUNT)
94 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) * \
95 EET_FILE2_DIRECTORY_ENTRY_COUNT)
96 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) * \
97 EET_FILE2_DICTIONARY_ENTRY_COUNT)
99 /* prototypes of internal calls */
101 eet_cache_find(const char *path,
105 eet_cache_add(Eet_File *ef,
110 eet_cache_del(Eet_File *ef,
115 eet_string_match(const char *s1,
119 eet_flush(Eet_File *ef);
122 eet_flush2(Eet_File *ef);
123 static Eet_File_Node *
124 find_node_by_name(Eet_File *ef,
127 read_data_from_disk(Eet_File *ef,
133 eet_internal_close(Eet_File *ef,
136 static Eina_Lock eet_cache_lock;
138 #define LOCK_CACHE eina_lock_take(&eet_cache_lock)
139 #define UNLOCK_CACHE eina_lock_release(&eet_cache_lock)
141 #define INIT_FILE(File) eina_lock_new(&File->file_lock)
142 #define LOCK_FILE(File) eina_lock_take(&File->file_lock)
143 #define UNLOCK_FILE(File) eina_lock_release(&File->file_lock)
144 #define DESTROY_FILE(File) eina_lock_free(&File->file_lock)
146 /* cache. i don't expect this to ever be large, so arrays will do */
147 static int eet_writers_num = 0;
148 static int eet_writers_alloc = 0;
149 static Eet_File **eet_writers = NULL;
150 static int eet_readers_num = 0;
151 static int eet_readers_alloc = 0;
152 static Eet_File **eet_readers = NULL;
153 static int eet_init_count = 0;
155 /* log domain variable */
156 int _eet_log_dom_global = -1;
158 /* Check to see its' an eet file pointer */
160 eet_check_pointer(const Eet_File *ef)
162 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
169 eet_check_header(const Eet_File *ef)
174 if (!ef->header->directory)
181 eet_test_close(int test,
186 ef->delete_me_now = 1;
187 eet_internal_close(ef, EINA_TRUE);
193 /* find an eet file in the currently in use cache */
195 eet_cache_find(const char *path,
202 for (i = 0; i < cache_num; i++)
204 /* if matches real path - return it */
205 if (eet_string_match(cache[i]->path, path))
206 if (!cache[i]->delete_me_now)
214 /* add to end of cache */
215 /* this should only be called when the cache lock is already held */
217 eet_cache_add(Eet_File *ef,
222 Eet_File **new_cache;
226 new_cache_num = *cache_num;
227 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
229 Eet_File *del_ef = NULL;
233 for (i = 0; i < new_cache_num; i++)
235 if (new_cache[i]->references == 0)
237 del_ef = new_cache[i];
244 del_ef->delete_me_now = 1;
245 eet_internal_close(del_ef, EINA_TRUE);
250 new_cache_num = *cache_num;
251 new_cache_alloc = *cache_alloc;
253 if (new_cache_num > new_cache_alloc)
255 new_cache_alloc += 16;
256 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
259 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
264 new_cache[new_cache_num - 1] = ef;
266 *cache_num = new_cache_num;
267 *cache_alloc = new_cache_alloc;
270 /* delete from cache */
271 /* this should only be called when the cache lock is already held */
273 eet_cache_del(Eet_File *ef,
278 Eet_File **new_cache;
279 int new_cache_num, new_cache_alloc;
283 new_cache_num = *cache_num;
284 new_cache_alloc = *cache_alloc;
285 if (new_cache_num <= 0)
288 for (i = 0; i < new_cache_num; i++)
290 if (new_cache[i] == ef)
294 if (i >= new_cache_num)
298 for (j = i; j < new_cache_num; j++)
299 new_cache[j] = new_cache[j + 1];
301 if (new_cache_num <= (new_cache_alloc - 16))
303 new_cache_alloc -= 16;
304 if (new_cache_num > 0)
306 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
309 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
321 *cache_num = new_cache_num;
322 *cache_alloc = new_cache_alloc;
325 /* internal string match. null friendly, catches same ptr */
327 eet_string_match(const char *s1,
330 /* both null- no match */
337 return !strcmp(s1, s2);
340 /* flush out writes to a v2 eet file */
342 eet_flush2(Eet_File *ef)
346 Eet_Error error = EET_ERROR_NONE;
347 int head[EET_FILE2_HEADER_COUNT];
348 int num_directory_entries = 0;
349 int num_dictionary_entries = 0;
350 int bytes_directory_entries = 0;
351 int bytes_dictionary_entries = 0;
352 int bytes_strings = 0;
354 int strings_offset = 0;
359 if (eet_check_pointer(ef))
360 return EET_ERROR_BAD_OBJECT;
362 if (eet_check_header(ef))
363 return EET_ERROR_EMPTY;
365 if (!ef->writes_pending)
366 return EET_ERROR_NONE;
368 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
369 || (ef->mode == EET_FILE_MODE_WRITE))
373 /* opening for write - delete old copy of file right away */
375 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
376 fp = fdopen(fd, "wb");
378 return EET_ERROR_NOT_WRITABLE;
380 fcntl(fd, F_SETFD, FD_CLOEXEC);
383 return EET_ERROR_NOT_WRITABLE;
385 /* calculate string base offset and data base offset */
386 num = (1 << ef->header->directory->size);
387 for (i = 0; i < num; ++i)
389 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
391 num_directory_entries++;
392 bytes_strings += strlen(efn->name) + 1;
397 num_dictionary_entries = ef->ed->count;
399 for (i = 0; i < num_dictionary_entries; ++i)
400 bytes_strings += ef->ed->all[i].len;
403 /* calculate section bytes size */
404 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
405 num_directory_entries + EET_FILE2_HEADER_SIZE;
406 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
407 num_dictionary_entries;
409 /* calculate per entry offset */
410 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
411 data_offset = bytes_directory_entries + bytes_dictionary_entries +
414 for (i = 0; i < num; ++i)
416 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
418 efn->offset = data_offset;
419 data_offset += efn->size;
421 efn->name_offset = strings_offset;
422 strings_offset += efn->name_size;
426 /* calculate dictionary strings offset */
428 ef->ed->offset = strings_offset;
430 /* go thru and write the header */
431 head[0] = (int)htonl((unsigned int)EET_MAGIC_FILE2);
432 head[1] = (int)htonl((unsigned int)num_directory_entries);
433 head[2] = (int)htonl((unsigned int)num_dictionary_entries);
435 fseek(fp, 0, SEEK_SET);
436 if (fwrite(head, sizeof (head), 1, fp) != 1)
439 /* write directories entry */
440 for (i = 0; i < num; i++)
442 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
445 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
447 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
448 flag |= efn->compression_type << 3;
450 ibuf[0] = (int)htonl((unsigned int)efn->offset);
451 ibuf[1] = (int)htonl((unsigned int)efn->size);
452 ibuf[2] = (int)htonl((unsigned int)efn->data_size);
453 ibuf[3] = (int)htonl((unsigned int)efn->name_offset);
454 ibuf[4] = (int)htonl((unsigned int)efn->name_size);
455 ibuf[5] = (int)htonl((unsigned int)flag);
457 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
462 /* write dictionary */
465 int offset = strings_offset;
467 for (j = 0; j < ef->ed->count; ++j)
469 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
471 sbuf[0] = (int)htonl((unsigned int)ef->ed->all[j].hash);
472 sbuf[1] = (int)htonl((unsigned int)offset);
473 sbuf[2] = (int)htonl((unsigned int)ef->ed->all[j].len);
474 sbuf[3] = (int)htonl((unsigned int)ef->ed->all[j].prev);
475 sbuf[4] = (int)htonl((unsigned int)ef->ed->all[j].next);
477 offset += ef->ed->all[j].len;
479 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
484 /* write directories name */
485 for (i = 0; i < num; i++)
487 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
489 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
496 for (j = 0; j < ef->ed->count; ++j)
498 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
503 for (i = 0; i < num; i++)
505 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
507 if (fwrite(efn->data, efn->size, 1, fp) != 1)
512 /* flush all write to the file. */
515 /* append signature if required */
518 error = eet_identity_sign(fp, ef->key);
519 if (error != EET_ERROR_NONE)
523 /* no more writes pending */
524 ef->writes_pending = 0;
528 return EET_ERROR_NONE;
535 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
537 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
539 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
541 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
543 default: error = EET_ERROR_WRITE_ERROR; break;
555 if (++eet_init_count != 1)
556 return eet_init_count;
559 return --eet_init_count;
561 _eet_log_dom_global = eina_log_domain_register("eet", EET_DEFAULT_LOG_COLOR);
562 if (_eet_log_dom_global < 0)
564 EINA_LOG_ERR("Eet Can not create a general log domain.");
568 eina_lock_new(&eet_cache_lock);
570 if (!eet_mempool_init())
572 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
573 goto unregister_log_domain;
576 if (!eet_node_init())
578 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
579 goto shutdown_mempool;
583 /* Before the library can be used, it must initialize itself if needed. */
584 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
586 gcry_check_version(NULL);
587 /* Disable warning messages about problems with the secure memory subsystem.
588 This command should be run right after gcry_check_version. */
589 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
590 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
591 enabling the use of secure memory. It also drops all extra privileges the
592 process has (i.e. if it is run as setuid (root)). If the argument nbytes
593 is 0, secure memory will be disabled. The minimum amount of secure memory
594 allocated is currently 16384 bytes; you may thus use a value of 1 to
595 request that default size. */
597 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
599 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
602 # ifdef EINA_HAVE_THREADS
603 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
605 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
607 # endif /* ifdef EINA_HAVE_THREADS */
608 if (gnutls_global_init())
611 #endif /* ifdef HAVE_GNUTLS */
613 ERR_load_crypto_strings();
614 OpenSSL_add_all_algorithms();
615 #endif /* ifdef HAVE_OPENSSL */
617 return eet_init_count;
624 eet_mempool_shutdown();
625 unregister_log_domain:
626 eina_log_domain_unregister(_eet_log_dom_global);
627 _eet_log_dom_global = -1;
630 return --eet_init_count;
636 if (eet_init_count <= 0)
638 ERR("Init count not greater than 0 in shutdown.");
641 if (--eet_init_count != 0)
642 return eet_init_count;
646 if (eet_writers_num || eet_readers_num)
648 Eet_File **closelist = NULL;
652 closelist = alloca((eet_writers_num + eet_readers_num)
653 * sizeof(Eet_File *));
654 for (i = 0; i < eet_writers_num; i++)
656 closelist[num++] = eet_writers[i];
657 eet_writers[i]->delete_me_now = 1;
660 for (i = 0; i < eet_readers_num; i++)
662 closelist[num++] = eet_readers[i];
663 eet_readers[i]->delete_me_now = 1;
666 for (i = 0; i < num; i++)
668 ERR("File '%s' is still open !", closelist[i]->path);
669 eet_internal_close(closelist[i], EINA_TRUE);
673 eet_mempool_shutdown();
675 eina_lock_free(&eet_cache_lock);
678 /* Note that gnutls has a leak where it doesnt free stuff it alloced
679 * on init. valgrind trace here:
680 * 21 bytes in 1 blocks are definitely lost in loss record 24 of 194
681 * at 0x4C2B6CD: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
682 * by 0x68AC801: strdup (strdup.c:43)
683 * by 0xD215B6A: p11_kit_registered_module_to_name (in /usr/lib/x86_64-linux-gnu/libp11-kit.so.0.0.0)
684 * by 0x9571574: gnutls_pkcs11_init (in /usr/lib/x86_64-linux-gnu/libgnutls.so.26.21.8)
685 * by 0x955B031: gnutls_global_init (in /usr/lib/x86_64-linux-gnu/libgnutls.so.26.21.8)
686 * by 0x6DFD6D0: eet_init (eet_lib.c:608)
688 * yes - i've tried calling gnutls_pkcs11_deinit() by hand but no luck.
689 * the leak is in there.
691 gnutls_global_deinit();
692 #endif /* ifdef HAVE_GNUTLS */
696 #endif /* ifdef HAVE_OPENSSL */
697 eina_log_domain_unregister(_eet_log_dom_global);
698 _eet_log_dom_global = -1;
701 return eet_init_count;
705 eet_sync(Eet_File *ef)
709 if (eet_check_pointer(ef))
710 return EET_ERROR_BAD_OBJECT;
712 if ((ef->mode != EET_FILE_MODE_WRITE) &&
713 (ef->mode != EET_FILE_MODE_READ_WRITE))
714 return EET_ERROR_NOT_WRITABLE;
716 if (!ef->writes_pending)
717 return EET_ERROR_NONE;
721 ret = eet_flush2(ef);
734 * We need to compute the list of eet file to close separately from the cache,
735 * due to eet_close removing them from the cache after each call.
738 for (i = 0; i < eet_writers_num; i++)
740 if (eet_writers[i]->references <= 0)
744 for (i = 0; i < eet_readers_num; i++)
746 if (eet_readers[i]->references <= 0)
752 Eet_File **closelist = NULL;
754 closelist = alloca(num * sizeof(Eet_File *));
756 for (i = 0; i < eet_writers_num; i++)
758 if (eet_writers[i]->references <= 0)
760 closelist[num] = eet_writers[i];
761 eet_writers[i]->delete_me_now = 1;
766 for (i = 0; i < eet_readers_num; i++)
768 if (eet_readers[i]->references <= 0)
770 closelist[num] = eet_readers[i];
771 eet_readers[i]->delete_me_now = 1;
776 for (i = 0; i < num; i++)
778 eet_internal_close(closelist[i], EINA_TRUE);
785 /* FIXME: MMAP race condition in READ_WRITE_MODE */
787 eet_internal_read2(Eet_File *ef)
789 const int *data = (const int *)ef->data;
790 const char *start = (const char *)ef->data;
792 unsigned long int bytes_directory_entries;
793 unsigned long int bytes_dictionary_entries;
794 unsigned long int signature_base_offset;
795 unsigned long int num_directory_entries;
796 unsigned long int num_dictionary_entries;
800 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
805 #define GET_INT(Value, Pointer, Index) \
807 Value = ntohl(*Pointer); \
809 Index += sizeof(int); \
812 /* get entries count and byte count */
813 GET_INT(num_directory_entries, data, idx);
814 /* get dictionary count and byte count */
815 GET_INT(num_dictionary_entries, data, idx);
817 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
818 num_directory_entries + EET_FILE2_HEADER_SIZE;
819 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
820 num_dictionary_entries;
822 /* we can't have > 0x7fffffff values here - invalid */
823 if (eet_test_close((num_directory_entries > 0x7fffffff), ef))
826 /* we can't have more bytes directory and bytes in dictionaries than the size of the file */
827 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
831 /* allocate header */
832 ef->header = eet_file_header_calloc(1);
833 if (eet_test_close(!ef->header, ef))
836 ef->header->magic = EET_MAGIC_FILE_HEADER;
838 /* allocate directory block in ram */
839 ef->header->directory = eet_file_directory_calloc(1);
840 if (eet_test_close(!ef->header->directory, ef))
843 /* 8 bit hash table (256 buckets) */
844 ef->header->directory->size = 8;
845 /* allocate base hash table */
846 ef->header->directory->nodes =
847 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
848 if (eet_test_close(!ef->header->directory->nodes, ef))
851 signature_base_offset = 0;
852 if (num_directory_entries == 0)
854 signature_base_offset = ef->data_size;
857 /* actually read the directory block - all of it, into ram */
858 for (i = 0; i < num_directory_entries; ++i)
862 unsigned long int name_offset;
863 unsigned long int name_size;
867 /* out directory block is inconsistent - we have overrun our */
868 /* dynamic block buffer before we finished scanning dir entries */
869 efn = eet_file_node_malloc(1);
870 if (eet_test_close(!efn, ef))
872 if (efn) eet_file_node_mp_free(efn); /* yes i know - we only get here if
873 * efn is null/0 -> trying to shut up
874 * warning tools like cppcheck */
878 /* get entrie header */
879 GET_INT(efn->offset, data, idx);
880 GET_INT(efn->size, data, idx);
881 GET_INT(efn->data_size, data, idx);
882 GET_INT(name_offset, data, idx);
883 GET_INT(name_size, data, idx);
884 GET_INT(flag, data, idx);
886 efn->compression = flag & 0x1 ? 1 : 0;
887 efn->ciphered = flag & 0x2 ? 1 : 0;
888 efn->alias = flag & 0x4 ? 1 : 0;
889 efn->compression_type = (flag >> 3) & 0xff;
891 #define EFN_TEST(Test, Ef, Efn) \
892 if (eet_test_close(Test, Ef)) \
894 eet_file_node_mp_free(Efn); \
898 /* check data pointer position */
899 EFN_TEST(!((efn->size > 0)
900 && (efn->offset + efn->size <= ef->data_size)
901 && (efn->offset > bytes_dictionary_entries +
902 bytes_directory_entries)), ef, efn);
904 /* check name position */
905 EFN_TEST(!((name_size > 0)
906 && (name_offset + name_size < ef->data_size)
907 && (name_offset >= bytes_dictionary_entries +
908 bytes_directory_entries)), ef, efn);
910 name = start + name_offset;
912 /* check '\0' at the end of name string */
913 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
916 efn->name = (char *)name;
917 efn->name_size = name_size;
919 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
920 efn->next = ef->header->directory->nodes[hash];
921 ef->header->directory->nodes[hash] = efn;
923 /* read-only mode, so currently we have no data loaded */
924 if (ef->mode == EET_FILE_MODE_READ)
925 efn->data = NULL; /* read-write mode - read everything into ram */
928 efn->data = malloc(efn->size);
930 memcpy(efn->data, ef->data + efn->offset, efn->size);
933 /* compute the possible position of a signature */
934 if (signature_base_offset < efn->offset + efn->size)
935 signature_base_offset = efn->offset + efn->size;
940 if (num_dictionary_entries)
942 const int *dico = (const int *)ef->data +
943 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
944 EET_FILE2_HEADER_COUNT;
947 if (eet_test_close((num_dictionary_entries *
948 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
949 (bytes_dictionary_entries + bytes_directory_entries),
953 ef->ed = eet_dictionary_add();
954 if (eet_test_close(!ef->ed, ef))
957 ef->ed->all = calloc(1, num_dictionary_entries * sizeof(Eet_String));
958 if (eet_test_close(!ef->ed->all, ef))
961 ef->ed->count = num_dictionary_entries;
962 ef->ed->total = num_dictionary_entries;
963 ef->ed->start = start + bytes_dictionary_entries +
964 bytes_directory_entries;
965 ef->ed->end = ef->ed->start;
967 for (j = 0; j < ef->ed->count; ++j)
972 GET_INT(hash, dico, idx);
973 GET_INT(offset, dico, idx);
974 GET_INT(ef->ed->all[j].len, dico, idx);
975 GET_INT(ef->ed->all[j].prev, dico, idx);
976 GET_INT(ef->ed->all[j].next, dico, idx);
978 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
979 So stick to int and check the value. */
980 if (eet_test_close(hash & 0xFFFFFF00, ef))
983 /* Check string position */
984 if (eet_test_close(!((ef->ed->all[j].len > 0)
986 (bytes_dictionary_entries +
987 bytes_directory_entries))
988 && (offset + ef->ed->all[j].len <
989 ef->data_size)), ef))
992 ef->ed->all[j].str = start + offset;
994 if (ef->ed->all[j].str + ef->ed->all[j].len > ef->ed->end)
995 ef->ed->end = ef->ed->all[j].str + ef->ed->all[j].len;
997 /* Check '\0' at the end of the string */
998 if (eet_test_close(ef->ed->all[j].str[ef->ed->all[j].len - 1] !=
1002 ef->ed->all[j].hash = hash;
1003 if (ef->ed->all[j].prev == -1)
1004 ef->ed->hash[hash] = j;
1006 /* compute the possible position of a signature */
1007 if (signature_base_offset < offset + ef->ed->all[j].len)
1008 signature_base_offset = offset + ef->ed->all[j].len;
1012 /* Check if the file is signed */
1013 ef->x509_der = NULL;
1014 ef->x509_length = 0;
1015 ef->signature = NULL;
1016 ef->signature_length = 0;
1018 if (signature_base_offset < ef->data_size)
1020 #ifdef HAVE_SIGNATURE
1021 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1022 signature_base_offset;
1023 ef->x509_der = eet_identity_check(ef->data,
1024 signature_base_offset,
1028 ef->data_size - signature_base_offset,
1030 &ef->signature_length,
1033 if (eet_test_close(!ef->x509_der, ef))
1036 #else /* ifdef HAVE_SIGNATURE */
1038 "This file could be signed but you didn't compile the necessary code to check the signature.");
1039 #endif /* ifdef HAVE_SIGNATURE */
1045 #if EET_OLD_EET_FILE_FORMAT
1047 eet_internal_read1(Eet_File *ef)
1049 const unsigned char *dyn_buf = NULL;
1050 const unsigned char *p = NULL;
1051 unsigned long int byte_entries;
1052 unsigned long int num_entries;
1057 "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.",
1060 /* build header table if read mode */
1063 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1066 #define EXTRACT_INT(Value, Pointer, Index) \
1069 memcpy(&tmp, Pointer + Index, sizeof(int)); \
1070 Value = ntohl(tmp); \
1071 Index += sizeof(int); \
1074 /* get entries count and byte count */
1075 EXTRACT_INT(num_entries, ef->data, idx);
1076 EXTRACT_INT(byte_entries, ef->data, idx);
1078 /* we can't have <= 0 values here - invalid */
1079 if (eet_test_close((num_entries > 0x7fffffff) ||
1080 (byte_entries > 0x7fffffff), ef))
1083 /* we can't have more entires than minimum bytes for those! invalid! */
1084 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1087 /* check we will not outrun the file limit */
1088 if (eet_test_close(((byte_entries + (int)(sizeof(int) * 3)) >
1089 ef->data_size), ef))
1092 /* allocate header */
1093 ef->header = eet_file_header_calloc(1);
1094 if (eet_test_close(!ef->header, ef))
1097 ef->header->magic = EET_MAGIC_FILE_HEADER;
1099 /* allocate directory block in ram */
1100 ef->header->directory = eet_file_directory_calloc(1);
1101 if (eet_test_close(!ef->header->directory, ef))
1104 /* 8 bit hash table (256 buckets) */
1105 ef->header->directory->size = 8;
1106 /* allocate base hash table */
1107 ef->header->directory->nodes =
1108 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1109 if (eet_test_close(!ef->header->directory->nodes, ef))
1112 /* actually read the directory block - all of it, into ram */
1113 dyn_buf = ef->data + idx;
1115 /* parse directory block */
1118 for (i = 0; i < num_entries; i++)
1127 #define HEADER_SIZE (sizeof(int) * 5)
1129 /* out directory block is inconsistent - we have overrun our */
1130 /* dynamic block buffer before we finished scanning dir entries */
1131 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1134 /* allocate all the ram needed for this stored node accounting */
1135 efn = eet_file_node_malloc(1);
1136 if (eet_test_close(!efn, ef))
1138 if (efn) eet_file_node_mp_free(efn); /* yes i know - we only get here if
1139 * efn is null/0 -> trying to shut up
1140 * warning tools like cppcheck */
1144 /* get entrie header */
1145 EXTRACT_INT(efn->offset, p, indexn);
1146 EXTRACT_INT(efn->compression, p, indexn);
1147 EXTRACT_INT(efn->size, p, indexn);
1148 EXTRACT_INT(efn->data_size, p, indexn);
1149 EXTRACT_INT(name_size, p, indexn);
1151 efn->name_size = name_size;
1156 if (eet_test_close(efn->size <= 0, ef))
1158 eet_file_node_mp_free(efn);
1162 /* invalid name_size */
1163 if (eet_test_close(name_size <= 0, ef))
1165 eet_file_node_mp_free(efn);
1169 /* reading name would mean falling off end of dyn_buf - invalid */
1170 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1172 eet_file_node_mp_free(efn);
1176 /* This code is useless if we dont want backward compatibility */
1178 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1181 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1185 efn->name = malloc(sizeof(char) * name_size + 1);
1186 if (eet_test_close(!efn->name, ef))
1188 eet_file_node_mp_free(efn);
1192 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1193 efn->name[name_size] = 0;
1196 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1201 /* The only really useful peace of code for efn->name (no backward compatibility) */
1202 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1204 /* get hash bucket it should go in */
1205 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1206 efn->next = ef->header->directory->nodes[hash];
1207 ef->header->directory->nodes[hash] = efn;
1209 /* read-only mode, so currently we have no data loaded */
1210 if (ef->mode == EET_FILE_MODE_READ)
1211 efn->data = NULL; /* read-write mode - read everything into ram */
1214 data = malloc(efn->size);
1216 memcpy(data, ef->data + efn->offset, efn->size);
1222 p += HEADER_SIZE + name_size;
1227 #endif /* if EET_OLD_EET_FILE_FORMAT */
1230 * this should only be called when the cache lock is already held
1231 * (We could drop this restriction if we add a parameter to eet_test_close
1232 * that indicates if the lock is held or not. For now it is easiest
1233 * to just require that it is always held.)
1236 eet_internal_read(Eet_File *ef)
1238 const int *data = (const int *)ef->data;
1240 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1243 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1246 switch (ntohl(*data))
1248 #if EET_OLD_EET_FILE_FORMAT
1249 case EET_MAGIC_FILE:
1250 return eet_internal_read1(ef);
1252 #endif /* if EET_OLD_EET_FILE_FORMAT */
1253 case EET_MAGIC_FILE2:
1254 return eet_internal_read2(ef);
1257 ef->delete_me_now = 1;
1258 eet_internal_close(ef, EINA_TRUE);
1266 eet_internal_close(Eet_File *ef,
1271 /* check to see its' an eet file pointer */
1272 if (eet_check_pointer(ef))
1273 return EET_ERROR_BAD_OBJECT;
1280 /* if its still referenced - dont go any further */
1281 if (ef->references > 0)
1283 /* flush any writes */
1284 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1285 (ef->mode == EET_FILE_MODE_READ_WRITE))
1290 err = eet_flush2(ef);
1292 eet_identity_unref(ef->key);
1295 /* if not urgent to delete it - dont free it - leave it in cache */
1296 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1299 /* remove from cache */
1300 if (ef->mode == EET_FILE_MODE_READ)
1301 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1302 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1303 (ef->mode == EET_FILE_MODE_READ_WRITE))
1304 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1306 /* we can unlock the cache now */
1315 if (ef->header->directory)
1317 if (ef->header->directory->nodes)
1321 num = (1 << ef->header->directory->size);
1322 for (i = 0; i < num; i++)
1326 while ((efn = ef->header->directory->nodes[i]))
1331 ef->header->directory->nodes[i] = efn->next;
1336 eet_file_node_mp_free(efn);
1339 free(ef->header->directory->nodes);
1342 eet_file_directory_mp_free(ef->header->directory);
1345 eet_file_header_mp_free(ef->header);
1348 eet_dictionary_free(ef->ed);
1356 eina_file_map_free(ef->readfp, (void *)ef->data);
1358 eina_file_close(ef->readfp);
1361 /* zero out ram for struct - caution tactic against stale memory use */
1362 memset(ef, 0, sizeof(Eet_File));
1365 eina_stringshare_del(ef->path);
1366 eet_file_mp_free(ef);
1373 return EET_ERROR_NONE;
1377 eet_memopen_read(const void *data,
1382 if (!data || size == 0)
1385 ef = eet_file_malloc(1);
1393 ef->magic = EET_MAGIC_FILE;
1395 ef->mode = EET_FILE_MODE_READ;
1397 ef->delete_me_now = 1;
1400 ef->data_size = size;
1402 ef->sha1_length = 0;
1404 /* eet_internal_read expects the cache lock to be held when it is called */
1406 ef = eet_internal_read(ef);
1412 eet_file_get(Eet_File *ef)
1414 if (eet_check_pointer(ef)) return NULL;
1419 eet_open(const char *file,
1425 unsigned long int size;
1430 /* find the current file handle in cache*/
1433 if (mode == EET_FILE_MODE_READ)
1435 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1440 ef->delete_me_now = 1;
1441 eet_internal_close(ef, EINA_TRUE);
1444 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1446 else if ((mode == EET_FILE_MODE_WRITE) ||
1447 (mode == EET_FILE_MODE_READ_WRITE))
1449 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1452 ef->delete_me_now = 1;
1454 eet_internal_close(ef, EINA_TRUE);
1457 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1460 /* try open the file based on mode */
1461 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1463 /* Prevent garbage in futur comparison. */
1464 fp = eina_file_open(file, EINA_FALSE);
1471 size = eina_file_size_get(fp);
1473 if (size < ((int)sizeof(int) * 3))
1475 eina_file_close(fp);
1484 if (!fp && mode == EET_FILE_MODE_READ)
1489 if (mode != EET_FILE_MODE_WRITE)
1498 if (ef && ef->readfp != fp)
1500 ef->delete_me_now = 1;
1502 eet_internal_close(ef, EINA_TRUE);
1508 /* reference it up and return it */
1510 eina_file_close(fp);
1517 file_len = strlen(file) + 1;
1519 /* Allocate struct for eet file and have it zero'd out */
1520 ef = eet_file_malloc(1);
1524 /* fill some of the members */
1528 ef->path = eina_stringshare_add_length(file, file_len);
1529 ef->magic = EET_MAGIC_FILE;
1533 ef->writes_pending = 0;
1534 ef->delete_me_now = 0;
1538 ef->sha1_length = 0;
1540 ef->ed = (mode == EET_FILE_MODE_WRITE)
1541 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1542 eet_dictionary_add() : NULL;
1545 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1548 /* if we can't open - bail out */
1549 if (eet_test_close(!ef->readfp, ef))
1552 /* if we opened for read or read-write */
1553 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1555 ef->data_size = size;
1556 ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL);
1557 if (eet_test_close((ef->data == NULL), ef))
1560 ef = eet_internal_read(ef);
1567 if (ef->references == 1)
1569 if (ef->mode == EET_FILE_MODE_READ)
1570 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1571 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1572 (ef->mode == EET_FILE_MODE_READ_WRITE))
1573 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1585 eet_mode_get(Eet_File *ef)
1587 /* check to see its' an eet file pointer */
1588 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1589 return EET_FILE_MODE_INVALID;
1595 eet_identity_x509(Eet_File *ef,
1602 *der_length = ef->x509_length;
1604 return ef->x509_der;
1608 eet_identity_signature(Eet_File *ef,
1609 int *signature_length)
1614 if (signature_length)
1615 *signature_length = ef->signature_length;
1617 return ef->signature;
1621 eet_identity_sha1(Eet_File *ef,
1625 ef->sha1 = eet_identity_compute_sha1(ef->data,
1630 *sha1_length = ef->sha1_length;
1636 eet_identity_set(Eet_File *ef,
1642 return EET_ERROR_BAD_OBJECT;
1646 eet_identity_ref(ef->key);
1647 eet_identity_unref(tmp);
1649 /* flags that writes are pending */
1650 ef->writes_pending = 1;
1652 return EET_ERROR_NONE;
1656 eet_close(Eet_File *ef)
1658 return eet_internal_close(ef, EINA_FALSE);
1662 eet_read_cipher(Eet_File *ef,
1665 const char *cipher_key)
1669 unsigned long int size = 0;
1674 /* check to see its' an eet file pointer */
1675 if (eet_check_pointer(ef))
1681 if ((ef->mode != EET_FILE_MODE_READ) &&
1682 (ef->mode != EET_FILE_MODE_READ_WRITE))
1685 /* no header, return NULL */
1686 if (eet_check_header(ef))
1691 /* hunt hash bucket */
1692 efn = find_node_by_name(ef, name);
1696 /* get size (uncompressed, if compressed at all) */
1697 size = efn->data_size;
1700 data = malloc(size);
1704 /* uncompressed data */
1705 if (efn->compression == 0)
1707 void *data_deciphered = NULL;
1708 unsigned int data_deciphered_sz = 0;
1709 /* if we already have the data in ram... copy that */
1711 if (efn->ciphered && efn->size > size)
1714 data = realloc(data, efn->size);
1718 memcpy(data, efn->data, size);
1720 if (!read_data_from_disk(ef, efn, data, size))
1723 if (efn->ciphered && cipher_key)
1725 if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key),
1726 &data_deciphered, &data_deciphered_sz))
1728 if (data_deciphered)
1729 free(data_deciphered);
1735 data = data_deciphered;
1736 size = data_deciphered_sz;
1739 /* compressed data */
1742 void *tmp_data = NULL;
1743 void *data_deciphered = NULL;
1744 unsigned int data_deciphered_sz = 0;
1745 int free_tmp = 0, ret;
1746 int compr_size = efn->size;
1749 /* if we already have the data in ram... copy that */
1751 tmp_data = efn->data;
1754 tmp_data = malloc(compr_size);
1760 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1767 if (efn->ciphered && cipher_key)
1769 if (eet_decipher(tmp_data, compr_size, cipher_key,
1770 strlen(cipher_key), &data_deciphered,
1771 &data_deciphered_sz))
1776 if (data_deciphered)
1777 free(data_deciphered);
1785 tmp_data = data_deciphered;
1786 compr_size = data_deciphered_sz;
1791 switch (efn->compression_type)
1793 case EET_COMPRESSION_VERYFAST:
1794 case EET_COMPRESSION_SUPERFAST:
1795 ret = LZ4_uncompress(tmp_data, data, dlen);
1796 if (ret != compr_size)
1804 if (uncompress((Bytef *)data, &dlen,
1805 tmp_data, (uLongf)compr_size) != Z_OK)
1825 if (data[size - 1] != '\0')
1828 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1835 /* fill in return values */
1848 eet_read(Eet_File *ef,
1852 return eet_read_cipher(ef, name, size_ret, NULL);
1856 eet_read_direct(Eet_File *ef,
1861 const char *data = NULL;
1867 /* check to see its' an eet file pointer */
1868 if (eet_check_pointer(ef))
1874 if ((ef->mode != EET_FILE_MODE_READ) &&
1875 (ef->mode != EET_FILE_MODE_READ_WRITE))
1878 /* no header, return NULL */
1879 if (eet_check_header(ef))
1884 /* hunt hash bucket */
1885 efn = find_node_by_name(ef, name);
1889 /* trick to detect data in memory instead of mmaped from disk */
1890 if (efn->offset > ef->data_size && !efn->data)
1893 /* get size (uncompressed, if compressed at all) */
1894 size = efn->data_size;
1898 data = efn->data ? efn->data : ef->data + efn->offset;
1900 /* handle alias case */
1901 if (efn->compression)
1905 int compr_size = efn->size;
1908 tmp = malloc(compr_size);
1909 if (!tmp) goto on_error;
1910 switch (efn->compression_type)
1912 case EET_COMPRESSION_VERYFAST:
1913 case EET_COMPRESSION_SUPERFAST:
1914 ret = LZ4_uncompress(data, tmp, size);
1915 if (ret != compr_size)
1924 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1925 (uLongf)compr_size))
1932 if (tmp[compr_size - 1] != '\0')
1940 retptr = eet_read_direct(ef, tmp, size_ret);
1948 if (data[size - 1] != '\0')
1953 return eet_read_direct(ef, data, size_ret);
1956 /* uncompressed data */
1957 if ((efn->compression == 0) && (efn->ciphered == 0))
1958 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1962 /* fill in return values */
1976 eet_alias_get(Eet_File *ef,
1980 const char *data = NULL;
1983 /* check to see its' an eet file pointer */
1984 if (eet_check_pointer(ef))
1990 if ((ef->mode != EET_FILE_MODE_READ) &&
1991 (ef->mode != EET_FILE_MODE_READ_WRITE))
1994 /* no header, return NULL */
1995 if (eet_check_header(ef))
2000 /* hunt hash bucket */
2001 efn = find_node_by_name(ef, name);
2005 /* trick to detect data in memory instead of mmaped from disk */
2006 if (efn->offset > ef->data_size && !efn->data)
2009 /* get size (uncompressed, if compressed at all) */
2010 size = efn->data_size;
2012 if (!efn->alias) return NULL;
2013 data = efn->data ? efn->data : ef->data + efn->offset;
2015 /* handle alias case */
2016 if (efn->compression)
2020 int compr_size = efn->size;
2023 tmp = malloc(compr_size);
2024 if (!tmp) goto on_error;
2025 switch (efn->compression_type)
2027 case EET_COMPRESSION_VERYFAST:
2028 case EET_COMPRESSION_SUPERFAST:
2029 ret = LZ4_uncompress(data, tmp, size);
2030 if (ret != compr_size)
2039 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
2040 (uLongf)compr_size))
2047 if (tmp[compr_size - 1] != '\0')
2052 retptr = eina_stringshare_add(tmp);
2060 if (data[size - 1] != '\0')
2065 return eina_stringshare_add(data);
2073 eet_alias(Eet_File *ef,
2075 const char *destination,
2080 Eina_Bool exists_already = EINA_FALSE;
2081 int data_size, ret, hash, slen;
2083 /* check to see its' an eet file pointer */
2084 if (eet_check_pointer(ef))
2087 if ((!name) || (!destination))
2090 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2091 (ef->mode != EET_FILE_MODE_READ_WRITE))
2098 /* allocate header */
2099 ef->header = eet_file_header_calloc(1);
2103 ef->header->magic = EET_MAGIC_FILE_HEADER;
2104 /* allocate directory block in ram */
2105 ef->header->directory = eet_file_directory_calloc(1);
2106 if (!ef->header->directory)
2108 eet_file_header_mp_free(ef->header);
2113 /* 8 bit hash table (256 buckets) */
2114 ef->header->directory->size = 8;
2115 /* allocate base hash table */
2116 ef->header->directory->nodes =
2117 calloc(1, sizeof(Eet_File_Node *) *
2118 (1 << ef->header->directory->size));
2119 if (!ef->header->directory->nodes)
2121 eet_file_directory_mp_free(ef->header->directory);
2127 /* figure hash bucket */
2128 hash = _eet_hash_gen(name, ef->header->directory->size);
2130 slen = strlen(destination) + 1;
2132 12 + ((slen * 101) / 100)
2136 ret = LZ4_compressBound(slen);
2137 if ((ret > 0) && (ret > data_size)) data_size = ret;
2140 data2 = malloc(data_size);
2141 if (!data2) goto on_error;
2143 /* if we want to compress */
2148 case EET_COMPRESSION_VERYFAST:
2149 ret = LZ4_compressHC((const char *)destination, (char *)data2,
2158 case EET_COMPRESSION_SUPERFAST:
2159 ret = LZ4_compress((const char *)destination, (char *)data2,
2172 /* compress the data with max compression */
2173 buflen = (uLongf)data_size;
2174 if (compress2((Bytef *)data2, &buflen,
2175 (const Bytef *)destination,
2176 (uLong)slen, Z_BEST_COMPRESSION) != Z_OK)
2181 /* record compressed chunk size */
2182 data_size = (int)buflen;
2186 if ((data_size < 0) ||
2187 (data_size >= (int)(strlen(destination) + 1)))
2190 data_size = strlen(destination) + 1;
2196 data3 = realloc(data2, data_size);
2197 if (data3) data2 = data3;
2201 if (!comp) memcpy(data2, destination, data_size);
2203 /* Does this node already exist? */
2204 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2207 if ((efn->name) && (eet_string_match(efn->name, name)))
2212 efn->compression = !!comp;
2213 efn->compression_type = comp;
2214 efn->size = data_size;
2215 efn->data_size = strlen(destination) + 1;
2217 /* Put the offset above the limit to avoid direct access */
2218 efn->offset = ef->data_size + 1;
2219 exists_already = EINA_TRUE;
2223 if (!exists_already)
2225 efn = eet_file_node_malloc(1);
2232 efn->name = strdup(name);
2233 efn->name_size = strlen(efn->name) + 1;
2236 efn->next = ef->header->directory->nodes[hash];
2237 ef->header->directory->nodes[hash] = efn;
2238 /* Put the offset above the limit to avoid direct access */
2239 efn->offset = ef->data_size + 1;
2242 efn->compression = !!comp;
2243 efn->compression_type = comp;
2244 efn->size = data_size;
2245 efn->data_size = strlen(destination) + 1;
2249 /* flags that writes are pending */
2250 ef->writes_pending = 1;
2261 eet_write_cipher(Eet_File *ef,
2266 const char *cipher_key)
2270 int exists_already = 0, data_size, hash, ret;
2272 /* check to see its' an eet file pointer */
2273 if (eet_check_pointer(ef))
2276 if ((!name) || (!data) || (size <= 0))
2279 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2280 (ef->mode != EET_FILE_MODE_READ_WRITE))
2287 /* allocate header */
2288 ef->header = eet_file_header_calloc(1);
2292 ef->header->magic = EET_MAGIC_FILE_HEADER;
2293 /* allocate directory block in ram */
2294 ef->header->directory = eet_file_directory_calloc(1);
2295 if (!ef->header->directory)
2297 eet_file_header_mp_free(ef->header);
2302 /* 8 bit hash table (256 buckets) */
2303 ef->header->directory->size = 8;
2304 /* allocate base hash table */
2305 ef->header->directory->nodes =
2306 calloc(1, sizeof(Eet_File_Node *) *
2307 (1 << ef->header->directory->size));
2308 if (!ef->header->directory->nodes)
2310 eet_file_directory_mp_free(ef->header->directory);
2316 /* figure hash bucket */
2317 hash = _eet_hash_gen(name, ef->header->directory->size);
2321 data_size = comp ? 12 + ((size * 101) / 100) : size;
2324 ret = LZ4_compressBound(size);
2325 if ((ret > 0) && (ret > data_size)) data_size = ret;
2328 if (comp || !cipher_key)
2330 data2 = malloc(data_size);
2335 /* if we want to compress */
2340 case EET_COMPRESSION_VERYFAST:
2341 ret = LZ4_compressHC((const char *)data, (char *)data2, size);
2350 case EET_COMPRESSION_SUPERFAST:
2351 ret = LZ4_compress((const char *)data, (char *)data2, size);
2364 /* compress the data with max compression */
2365 buflen = (uLongf)data_size;
2366 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2367 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2373 /* record compressed chunk size */
2374 data_size = (int)buflen;
2377 if ((data_size < 0) || (data_size >= size))
2386 data3 = realloc(data2, data_size);
2394 void *data_ciphered = NULL;
2395 unsigned int data_ciphered_sz = 0;
2398 tmp = comp ? data2 : data;
2399 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2400 &data_ciphered, &data_ciphered_sz))
2405 data2 = data_ciphered;
2406 data_size = data_ciphered_sz;
2411 free(data_ciphered);
2418 memcpy(data2, data, size);
2421 /* Does this node already exist? */
2422 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2425 if ((efn->name) && (eet_string_match(efn->name, name)))
2429 efn->ciphered = cipher_key ? 1 : 0;
2430 efn->compression = !!comp;
2431 efn->compression_type = comp;
2432 efn->size = data_size;
2433 efn->data_size = size;
2435 /* Put the offset above the limit to avoid direct access */
2436 efn->offset = ef->data_size + 1;
2441 if (!exists_already)
2443 efn = eet_file_node_malloc(1);
2450 efn->name = strdup(name);
2451 efn->name_size = strlen(efn->name) + 1;
2454 efn->next = ef->header->directory->nodes[hash];
2455 ef->header->directory->nodes[hash] = efn;
2456 /* Put the offset above the limit to avoid direct access */
2457 efn->offset = ef->data_size + 1;
2459 efn->ciphered = cipher_key ? 1 : 0;
2460 efn->compression = !!comp;
2461 efn->compression_type = comp;
2462 efn->size = data_size;
2463 efn->data_size = size;
2467 /* flags that writes are pending */
2468 ef->writes_pending = 1;
2478 eet_write(Eet_File *ef,
2484 return eet_write_cipher(ef, name, data, size, comp, NULL);
2488 eet_delete(Eet_File *ef,
2492 Eet_File_Node *pefn;
2494 int exists_already = 0;
2496 /* check to see its' an eet file pointer */
2497 if (eet_check_pointer(ef))
2503 /* deleting keys is only possible in RW or WRITE mode */
2504 if (ef->mode == EET_FILE_MODE_READ)
2507 if (eet_check_header(ef))
2512 /* figure hash bucket */
2513 hash = _eet_hash_gen(name, ef->header->directory->size);
2515 /* Does this node already exist? */
2516 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2518 pefn = efn, efn = efn->next)
2521 if (eet_string_match(efn->name, name))
2527 ef->header->directory->nodes[hash] = efn->next;
2529 pefn->next = efn->next;
2534 eet_file_node_mp_free(efn);
2539 /* flags that writes are pending */
2541 ef->writes_pending = 1;
2545 /* update access time */
2546 return exists_already;
2549 EAPI Eet_Dictionary *
2550 eet_dictionary_get(Eet_File *ef)
2552 if (eet_check_pointer(ef))
2559 eet_list(Eet_File *ef,
2564 char **list_ret = NULL;
2566 int list_count_alloc = 0;
2569 /* check to see its' an eet file pointer */
2570 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2572 ((ef->mode != EET_FILE_MODE_READ) &&
2573 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2581 if (!strcmp(glob, "*"))
2586 /* loop through all entries */
2587 num = (1 << ef->header->directory->size);
2588 for (i = 0; i < num; i++)
2590 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2592 /* if the entry matches the input glob
2593 * check for * explicitly, because on some systems, * isn't well
2596 if ((!glob) || !fnmatch(glob, efn->name, 0))
2598 /* add it to our list */
2601 /* only realloc in 32 entry chunks */
2602 if (list_count > list_count_alloc)
2604 char **new_list = NULL;
2606 list_count_alloc += 64;
2608 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2616 list_ret = new_list;
2619 /* put pointer of name string in */
2620 list_ret[list_count - 1] = efn->name;
2627 /* return count and list */
2629 *count_ret = list_count;
2643 eet_num_entries(Eet_File *ef)
2645 int i, num, ret = 0;
2648 /* check to see its' an eet file pointer */
2649 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2650 ((ef->mode != EET_FILE_MODE_READ) &&
2651 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2656 /* loop through all entries */
2657 num = (1 << ef->header->directory->size);
2658 for (i = 0; i < num; i++)
2660 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2669 static Eet_File_Node *
2670 find_node_by_name(Eet_File *ef,
2676 /* get hash bucket this should be in */
2677 hash = _eet_hash_gen(name, ef->header->directory->size);
2679 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2681 if (eet_string_match(efn->name, name))
2689 read_data_from_disk(Eet_File *ef,
2694 if (efn->offset > ef->data_size)
2700 if ((efn->offset + len) > ef->data_size)
2703 memcpy(buf, ef->data + efn->offset, len);