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)
1501 if (ef && ef->readfp != fp)
1503 ef->delete_me_now = 1;
1505 eet_internal_close(ef, EINA_TRUE);
1511 /* reference it up and return it */
1513 eina_file_close(fp);
1520 file_len = strlen(file) + 1;
1522 /* Allocate struct for eet file and have it zero'd out */
1523 ef = eet_file_malloc(1);
1527 /* fill some of the members */
1531 ef->path = eina_stringshare_add_length(file, file_len);
1532 ef->magic = EET_MAGIC_FILE;
1536 ef->writes_pending = 0;
1537 ef->delete_me_now = 0;
1541 ef->sha1_length = 0;
1543 ef->ed = (mode == EET_FILE_MODE_WRITE)
1544 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1545 eet_dictionary_add() : NULL;
1548 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1551 /* if we can't open - bail out */
1552 if (eet_test_close(!ef->readfp, ef))
1555 /* if we opened for read or read-write */
1556 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1558 ef->data_size = size;
1559 ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL);
1560 if (eet_test_close((ef->data == NULL), ef))
1563 ef = eet_internal_read(ef);
1570 if (ef->references == 1)
1572 if (ef->mode == EET_FILE_MODE_READ)
1573 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1574 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1575 (ef->mode == EET_FILE_MODE_READ_WRITE))
1576 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1588 eet_mode_get(Eet_File *ef)
1590 /* check to see its' an eet file pointer */
1591 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1592 return EET_FILE_MODE_INVALID;
1598 eet_identity_x509(Eet_File *ef,
1605 *der_length = ef->x509_length;
1607 return ef->x509_der;
1611 eet_identity_signature(Eet_File *ef,
1612 int *signature_length)
1617 if (signature_length)
1618 *signature_length = ef->signature_length;
1620 return ef->signature;
1624 eet_identity_sha1(Eet_File *ef,
1628 ef->sha1 = eet_identity_compute_sha1(ef->data,
1633 *sha1_length = ef->sha1_length;
1639 eet_identity_set(Eet_File *ef,
1645 return EET_ERROR_BAD_OBJECT;
1649 eet_identity_ref(ef->key);
1650 eet_identity_unref(tmp);
1652 /* flags that writes are pending */
1653 ef->writes_pending = 1;
1655 return EET_ERROR_NONE;
1659 eet_close(Eet_File *ef)
1661 return eet_internal_close(ef, EINA_FALSE);
1665 eet_read_cipher(Eet_File *ef,
1668 const char *cipher_key)
1672 unsigned long int size = 0;
1677 /* check to see its' an eet file pointer */
1678 if (eet_check_pointer(ef))
1684 if ((ef->mode != EET_FILE_MODE_READ) &&
1685 (ef->mode != EET_FILE_MODE_READ_WRITE))
1688 /* no header, return NULL */
1689 if (eet_check_header(ef))
1694 /* hunt hash bucket */
1695 efn = find_node_by_name(ef, name);
1699 /* get size (uncompressed, if compressed at all) */
1700 size = efn->data_size;
1703 data = malloc(size);
1707 /* uncompressed data */
1708 if (efn->compression == 0)
1710 void *data_deciphered = NULL;
1711 unsigned int data_deciphered_sz = 0;
1712 /* if we already have the data in ram... copy that */
1714 if (efn->ciphered && efn->size > size)
1717 data = realloc(data, efn->size);
1721 memcpy(data, efn->data, size);
1723 if (!read_data_from_disk(ef, efn, data, size))
1726 if (efn->ciphered && cipher_key)
1728 if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key),
1729 &data_deciphered, &data_deciphered_sz))
1731 if (data_deciphered)
1732 free(data_deciphered);
1738 data = data_deciphered;
1739 size = data_deciphered_sz;
1742 /* compressed data */
1745 void *tmp_data = NULL;
1746 void *data_deciphered = NULL;
1747 unsigned int data_deciphered_sz = 0;
1748 int free_tmp = 0, ret;
1749 int compr_size = efn->size;
1752 /* if we already have the data in ram... copy that */
1754 tmp_data = efn->data;
1757 tmp_data = malloc(compr_size);
1763 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1770 if (efn->ciphered && cipher_key)
1772 if (eet_decipher(tmp_data, compr_size, cipher_key,
1773 strlen(cipher_key), &data_deciphered,
1774 &data_deciphered_sz))
1779 if (data_deciphered)
1780 free(data_deciphered);
1788 tmp_data = data_deciphered;
1789 compr_size = data_deciphered_sz;
1794 switch (efn->compression_type)
1796 case EET_COMPRESSION_VERYFAST:
1797 case EET_COMPRESSION_SUPERFAST:
1798 ret = LZ4_uncompress(tmp_data, data, dlen);
1799 if (ret != compr_size)
1807 if (uncompress((Bytef *)data, &dlen,
1808 tmp_data, (uLongf)compr_size) != Z_OK)
1828 if (data[size - 1] != '\0')
1831 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1838 /* fill in return values */
1851 eet_read(Eet_File *ef,
1855 return eet_read_cipher(ef, name, size_ret, NULL);
1859 eet_read_direct(Eet_File *ef,
1864 const char *data = NULL;
1870 /* check to see its' an eet file pointer */
1871 if (eet_check_pointer(ef))
1877 if ((ef->mode != EET_FILE_MODE_READ) &&
1878 (ef->mode != EET_FILE_MODE_READ_WRITE))
1881 /* no header, return NULL */
1882 if (eet_check_header(ef))
1887 /* hunt hash bucket */
1888 efn = find_node_by_name(ef, name);
1892 /* trick to detect data in memory instead of mmaped from disk */
1893 if (efn->offset > ef->data_size && !efn->data)
1896 /* get size (uncompressed, if compressed at all) */
1897 size = efn->data_size;
1901 data = efn->data ? efn->data : ef->data + efn->offset;
1903 /* handle alias case */
1904 if (efn->compression)
1908 int compr_size = efn->size;
1911 tmp = malloc(compr_size);
1912 if (!tmp) goto on_error;
1913 switch (efn->compression_type)
1915 case EET_COMPRESSION_VERYFAST:
1916 case EET_COMPRESSION_SUPERFAST:
1917 ret = LZ4_uncompress(data, tmp, size);
1918 if (ret != compr_size)
1927 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1928 (uLongf)compr_size))
1935 if (tmp[compr_size - 1] != '\0')
1943 retptr = eet_read_direct(ef, tmp, size_ret);
1951 if (data[size - 1] != '\0')
1956 return eet_read_direct(ef, data, size_ret);
1959 /* uncompressed data */
1960 if ((efn->compression == 0) && (efn->ciphered == 0))
1961 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1965 /* fill in return values */
1979 eet_alias_get(Eet_File *ef,
1983 const char *data = NULL;
1986 /* check to see its' an eet file pointer */
1987 if (eet_check_pointer(ef))
1993 if ((ef->mode != EET_FILE_MODE_READ) &&
1994 (ef->mode != EET_FILE_MODE_READ_WRITE))
1997 /* no header, return NULL */
1998 if (eet_check_header(ef))
2003 /* hunt hash bucket */
2004 efn = find_node_by_name(ef, name);
2008 /* trick to detect data in memory instead of mmaped from disk */
2009 if (efn->offset > ef->data_size && !efn->data)
2012 /* get size (uncompressed, if compressed at all) */
2013 size = efn->data_size;
2015 if (!efn->alias) return NULL;
2016 data = efn->data ? efn->data : ef->data + efn->offset;
2018 /* handle alias case */
2019 if (efn->compression)
2023 int compr_size = efn->size;
2026 tmp = malloc(compr_size);
2027 if (!tmp) goto on_error;
2028 switch (efn->compression_type)
2030 case EET_COMPRESSION_VERYFAST:
2031 case EET_COMPRESSION_SUPERFAST:
2032 ret = LZ4_uncompress(data, tmp, size);
2033 if (ret != compr_size)
2042 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
2043 (uLongf)compr_size))
2050 if (tmp[compr_size - 1] != '\0')
2055 retptr = eina_stringshare_add(tmp);
2063 if (data[size - 1] != '\0')
2068 return eina_stringshare_add(data);
2076 eet_alias(Eet_File *ef,
2078 const char *destination,
2083 Eina_Bool exists_already = EINA_FALSE;
2084 int data_size, ret, hash, slen;
2086 /* check to see its' an eet file pointer */
2087 if (eet_check_pointer(ef))
2090 if ((!name) || (!destination))
2093 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2094 (ef->mode != EET_FILE_MODE_READ_WRITE))
2101 /* allocate header */
2102 ef->header = eet_file_header_calloc(1);
2106 ef->header->magic = EET_MAGIC_FILE_HEADER;
2107 /* allocate directory block in ram */
2108 ef->header->directory = eet_file_directory_calloc(1);
2109 if (!ef->header->directory)
2111 eet_file_header_mp_free(ef->header);
2116 /* 8 bit hash table (256 buckets) */
2117 ef->header->directory->size = 8;
2118 /* allocate base hash table */
2119 ef->header->directory->nodes =
2120 calloc(1, sizeof(Eet_File_Node *) *
2121 (1 << ef->header->directory->size));
2122 if (!ef->header->directory->nodes)
2124 eet_file_directory_mp_free(ef->header->directory);
2130 /* figure hash bucket */
2131 hash = _eet_hash_gen(name, ef->header->directory->size);
2133 slen = strlen(destination) + 1;
2135 12 + ((slen * 101) / 100)
2139 ret = LZ4_compressBound(slen);
2140 if ((ret > 0) && (ret > data_size)) data_size = ret;
2143 data2 = malloc(data_size);
2144 if (!data2) goto on_error;
2146 /* if we want to compress */
2151 case EET_COMPRESSION_VERYFAST:
2152 ret = LZ4_compressHC((const char *)destination, (char *)data2,
2161 case EET_COMPRESSION_SUPERFAST:
2162 ret = LZ4_compress((const char *)destination, (char *)data2,
2175 /* compress the data with max compression */
2176 buflen = (uLongf)data_size;
2177 if (compress2((Bytef *)data2, &buflen,
2178 (const Bytef *)destination,
2179 (uLong)slen, Z_BEST_COMPRESSION) != Z_OK)
2184 /* record compressed chunk size */
2185 data_size = (int)buflen;
2189 if ((data_size < 0) ||
2190 (data_size >= (int)(strlen(destination) + 1)))
2193 data_size = strlen(destination) + 1;
2199 data3 = realloc(data2, data_size);
2200 if (data3) data2 = data3;
2204 if (!comp) memcpy(data2, destination, data_size);
2206 /* Does this node already exist? */
2207 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2210 if ((efn->name) && (eet_string_match(efn->name, name)))
2215 efn->compression = !!comp;
2216 efn->compression_type = comp;
2217 efn->size = data_size;
2218 efn->data_size = strlen(destination) + 1;
2220 /* Put the offset above the limit to avoid direct access */
2221 efn->offset = ef->data_size + 1;
2222 exists_already = EINA_TRUE;
2226 if (!exists_already)
2228 efn = eet_file_node_malloc(1);
2235 efn->name = strdup(name);
2236 efn->name_size = strlen(efn->name) + 1;
2239 efn->next = ef->header->directory->nodes[hash];
2240 ef->header->directory->nodes[hash] = efn;
2241 /* Put the offset above the limit to avoid direct access */
2242 efn->offset = ef->data_size + 1;
2245 efn->compression = !!comp;
2246 efn->compression_type = comp;
2247 efn->size = data_size;
2248 efn->data_size = strlen(destination) + 1;
2252 /* flags that writes are pending */
2253 ef->writes_pending = 1;
2264 eet_write_cipher(Eet_File *ef,
2269 const char *cipher_key)
2273 int exists_already = 0, data_size, hash, ret;
2275 /* check to see its' an eet file pointer */
2276 if (eet_check_pointer(ef))
2279 if ((!name) || (!data) || (size <= 0))
2282 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2283 (ef->mode != EET_FILE_MODE_READ_WRITE))
2290 /* allocate header */
2291 ef->header = eet_file_header_calloc(1);
2295 ef->header->magic = EET_MAGIC_FILE_HEADER;
2296 /* allocate directory block in ram */
2297 ef->header->directory = eet_file_directory_calloc(1);
2298 if (!ef->header->directory)
2300 eet_file_header_mp_free(ef->header);
2305 /* 8 bit hash table (256 buckets) */
2306 ef->header->directory->size = 8;
2307 /* allocate base hash table */
2308 ef->header->directory->nodes =
2309 calloc(1, sizeof(Eet_File_Node *) *
2310 (1 << ef->header->directory->size));
2311 if (!ef->header->directory->nodes)
2313 eet_file_directory_mp_free(ef->header->directory);
2319 /* figure hash bucket */
2320 hash = _eet_hash_gen(name, ef->header->directory->size);
2324 data_size = comp ? 12 + ((size * 101) / 100) : size;
2327 ret = LZ4_compressBound(size);
2328 if ((ret > 0) && (ret > data_size)) data_size = ret;
2331 if (comp || !cipher_key)
2333 data2 = malloc(data_size);
2338 /* if we want to compress */
2343 case EET_COMPRESSION_VERYFAST:
2344 ret = LZ4_compressHC((const char *)data, (char *)data2, size);
2353 case EET_COMPRESSION_SUPERFAST:
2354 ret = LZ4_compress((const char *)data, (char *)data2, size);
2367 /* compress the data with max compression */
2368 buflen = (uLongf)data_size;
2369 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2370 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2376 /* record compressed chunk size */
2377 data_size = (int)buflen;
2380 if ((data_size < 0) || (data_size >= size))
2389 data3 = realloc(data2, data_size);
2397 void *data_ciphered = NULL;
2398 unsigned int data_ciphered_sz = 0;
2401 tmp = comp ? data2 : data;
2402 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2403 &data_ciphered, &data_ciphered_sz))
2408 data2 = data_ciphered;
2409 data_size = data_ciphered_sz;
2414 free(data_ciphered);
2421 memcpy(data2, data, size);
2424 /* Does this node already exist? */
2425 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2428 if ((efn->name) && (eet_string_match(efn->name, name)))
2432 efn->ciphered = cipher_key ? 1 : 0;
2433 efn->compression = !!comp;
2434 efn->compression_type = comp;
2435 efn->size = data_size;
2436 efn->data_size = size;
2438 /* Put the offset above the limit to avoid direct access */
2439 efn->offset = ef->data_size + 1;
2444 if (!exists_already)
2446 efn = eet_file_node_malloc(1);
2453 efn->name = strdup(name);
2454 efn->name_size = strlen(efn->name) + 1;
2457 efn->next = ef->header->directory->nodes[hash];
2458 ef->header->directory->nodes[hash] = efn;
2459 /* Put the offset above the limit to avoid direct access */
2460 efn->offset = ef->data_size + 1;
2462 efn->ciphered = cipher_key ? 1 : 0;
2463 efn->compression = !!comp;
2464 efn->compression_type = comp;
2465 efn->size = data_size;
2466 efn->data_size = size;
2470 /* flags that writes are pending */
2471 ef->writes_pending = 1;
2481 eet_write(Eet_File *ef,
2487 return eet_write_cipher(ef, name, data, size, comp, NULL);
2491 eet_delete(Eet_File *ef,
2495 Eet_File_Node *pefn;
2497 int exists_already = 0;
2499 /* check to see its' an eet file pointer */
2500 if (eet_check_pointer(ef))
2506 /* deleting keys is only possible in RW or WRITE mode */
2507 if (ef->mode == EET_FILE_MODE_READ)
2510 if (eet_check_header(ef))
2515 /* figure hash bucket */
2516 hash = _eet_hash_gen(name, ef->header->directory->size);
2518 /* Does this node already exist? */
2519 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2521 pefn = efn, efn = efn->next)
2524 if (eet_string_match(efn->name, name))
2530 ef->header->directory->nodes[hash] = efn->next;
2532 pefn->next = efn->next;
2537 eet_file_node_mp_free(efn);
2542 /* flags that writes are pending */
2544 ef->writes_pending = 1;
2548 /* update access time */
2549 return exists_already;
2552 EAPI Eet_Dictionary *
2553 eet_dictionary_get(Eet_File *ef)
2555 if (eet_check_pointer(ef))
2562 eet_list(Eet_File *ef,
2567 char **list_ret = NULL;
2569 int list_count_alloc = 0;
2572 /* check to see its' an eet file pointer */
2573 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2575 ((ef->mode != EET_FILE_MODE_READ) &&
2576 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2584 if (!strcmp(glob, "*"))
2589 /* loop through all entries */
2590 num = (1 << ef->header->directory->size);
2591 for (i = 0; i < num; i++)
2593 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2595 /* if the entry matches the input glob
2596 * check for * explicitly, because on some systems, * isn't well
2599 if ((!glob) || !fnmatch(glob, efn->name, 0))
2601 /* add it to our list */
2604 /* only realloc in 32 entry chunks */
2605 if (list_count > list_count_alloc)
2607 char **new_list = NULL;
2609 list_count_alloc += 64;
2611 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2619 list_ret = new_list;
2622 /* put pointer of name string in */
2623 list_ret[list_count - 1] = efn->name;
2630 /* return count and list */
2632 *count_ret = list_count;
2646 eet_num_entries(Eet_File *ef)
2648 int i, num, ret = 0;
2651 /* check to see its' an eet file pointer */
2652 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2653 ((ef->mode != EET_FILE_MODE_READ) &&
2654 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2659 /* loop through all entries */
2660 num = (1 << ef->header->directory->size);
2661 for (i = 0; i < num; i++)
2663 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2672 static Eet_File_Node *
2673 find_node_by_name(Eet_File *ef,
2679 /* get hash bucket this should be in */
2680 hash = _eet_hash_gen(name, ef->header->directory->size);
2682 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2684 if (eet_string_match(efn->name, name))
2692 read_data_from_disk(Eet_File *ef,
2697 if (efn->offset > ef->data_size)
2703 if ((efn->offset + len) > ef->data_size)
2706 memcpy(buf, ef->data + efn->offset, len);