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 */
19 void * alloca (size_t);
20 #endif /* ifdef HAVE_ALLOCA_H */
23 # include <winsock2.h>
24 #endif /* ifdef _WIN32 */
28 #include <sys/types.h>
39 #endif /* ifndef _MSC_VER */
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif /* ifdef HAVE_NETINET_IN_H */
47 #endif /* ifdef HAVE_EVIL */
50 # include <gnutls/gnutls.h>
52 #endif /* ifdef HAVE_GNUTLS */
55 # include <openssl/err.h>
56 # include <openssl/evp.h>
57 #endif /* ifdef HAVE_OPENSSL */
59 #ifdef EFL_HAVE_POSIX_THREADS
62 GCRY_THREAD_OPTION_PTHREAD_IMPL;
63 # endif /* ifdef HAVE_GNUTLS */
64 #endif /* ifdef EFL_HAVE_POSIX_THREADS */
69 #include "Eet_private.h"
71 static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
72 EAPI Eet_Version *eet_version = &_version;
76 #endif /* ifdef HAVE_REALPATH */
78 #define EET_MAGIC_FILE 0x1ee7ff00
79 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
81 #define EET_MAGIC_FILE2 0x1ee70f42
83 typedef struct _Eet_File_Header Eet_File_Header;
84 typedef struct _Eet_File_Node Eet_File_Node;
85 typedef struct _Eet_File_Directory Eet_File_Directory;
91 Eet_File_Header *header;
94 const unsigned char *data;
96 const void *signature;
106 unsigned int signature_length;
111 #ifdef EFL_HAVE_THREADS
112 # ifdef EFL_HAVE_POSIX_THREADS
113 pthread_mutex_t file_lock;
114 # else /* ifdef EFL_HAVE_POSIX_THREADS */
116 # endif /* ifdef EFL_HAVE_POSIX_THREADS */
117 #endif /* ifdef EFL_HAVE_THREADS */
119 unsigned char writes_pending : 1;
120 unsigned char delete_me_now : 1;
123 struct _Eet_File_Header
126 Eet_File_Directory *directory;
129 struct _Eet_File_Directory
132 Eet_File_Node **nodes;
135 struct _Eet_File_Node
139 Eet_File_Node *next; /* FIXME: make buckets linked lists */
142 int dictionary_offset;
149 unsigned char free_name : 1;
150 unsigned char compression : 1;
151 unsigned char ciphered : 1;
152 unsigned char alias : 1;
157 /* NB: all int's are stored in network byte order on disk */
159 int magic; /* magic number ie 0x1ee7ff00 */
160 int num_directory_entries; /* number of directory entries to follow */
161 int bytes_directory_entries; /* bytes of directory entries to follow */
164 int offset; /* bytes offset into file for data chunk */
165 int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
166 int size; /* size of the data chunk */
167 int data_size; /* size of the (uncompressed) data chunk */
168 int name_size; /* length in bytes of the name field */
169 char name[name_size]; /* name string (variable length) and \0 terminated */
170 } directory[num_directory_entries];
171 /* and now startes the data stream... */
176 /* NB: all int's are stored in network byte order on disk */
178 int magic; /* magic number ie 0x1ee70f42 */
179 int num_directory_entries; /* number of directory entries to follow */
180 int num_dictionary_entries; /* number of dictionary entries to follow */
183 int data_offset; /* bytes offset into file for data chunk */
184 int size; /* size of the data chunk */
185 int data_size; /* size of the (uncompressed) data chunk */
186 int name_offset; /* bytes offset into file for name string */
187 int name_size; /* length in bytes of the name field */
188 int flags; /* bit flags - for now:
189 bit 0 => compresion on/off
190 bit 1 => ciphered on/off
193 } directory[num_directory_entries];
201 } dictionary[num_dictionary_entries];
202 /* now start the string stream. */
203 /* and right after them the data stream. */
204 int magic_sign; /* Optional, only if the eet file is signed. */
205 int signature_length; /* Signature length. */
206 int x509_length; /* Public certificate that signed the file. */
207 char signature[signature_length]; /* The signature. */
208 char x509[x509_length]; /* The public certificate. */
211 #define EET_FILE2_HEADER_COUNT 3
212 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
213 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
215 #define EET_FILE2_HEADER_SIZE (sizeof(int) *\
216 EET_FILE2_HEADER_COUNT)
217 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) *\
218 EET_FILE2_DIRECTORY_ENTRY_COUNT)
219 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) *\
220 EET_FILE2_DICTIONARY_ENTRY_COUNT)
222 /* prototypes of internal calls */
223 static Eet_File * eet_cache_find(const char *path,
226 static void eet_cache_add(Eet_File *ef,
230 static void eet_cache_del(Eet_File *ef,
234 static int eet_string_match(const char *s1, const char *s2);
236 static Eet_Error eet_flush(Eet_File *ef);
238 static Eet_Error eet_flush2(Eet_File *ef);
239 static Eet_File_Node * find_node_by_name(Eet_File *ef, const char *name);
240 static int read_data_from_disk(Eet_File *ef,
245 static Eet_Error eet_internal_close(Eet_File *ef, Eina_Bool locked);
247 #ifdef EFL_HAVE_THREADS
249 # ifdef EFL_HAVE_POSIX_THREADS
251 static pthread_mutex_t eet_cache_lock = PTHREAD_MUTEX_INITIALIZER;
253 # define LOCK_CACHE pthread_mutex_lock(&eet_cache_lock)
254 # define UNLOCK_CACHE pthread_mutex_unlock(&eet_cache_lock)
256 # define INIT_FILE(File) pthread_mutex_init(&File->file_lock, NULL)
257 # define LOCK_FILE(File) pthread_mutex_lock(&File->file_lock)
258 # define UNLOCK_FILE(File) pthread_mutex_unlock(&File->file_lock)
259 # define DESTROY_FILE(File) pthread_mutex_destroy(&File->file_lock)
261 # else /* EFL_HAVE_WIN32_THREADS */
263 static HANDLE eet_cache_lock = NULL;
265 # define LOCK_CACHE WaitForSingleObject(eet_cache_lock, INFINITE)
266 # define UNLOCK_CACHE ReleaseMutex(eet_cache_lock)
268 # define INIT_FILE(File) File->file_lock = CreateMutex(NULL, FALSE, NULL)
269 # define LOCK_FILE(File) WaitForSingleObject(File->file_lock, INFINITE)
270 # define UNLOCK_FILE(File) ReleaseMutex(File->file_lock)
271 # define DESTROY_FILE(File) CloseHandle(File->file_lock)
273 # endif /* EFL_HAVE_WIN32_THREADS */
275 #else /* ifdef EFL_HAVE_THREADS */
277 # define LOCK_CACHE do {} while (0)
278 # define UNLOCK_CACHE do {} while (0)
280 # define INIT_FILE(File) do {} while (0)
281 # define LOCK_FILE(File) do {} while (0)
282 # define UNLOCK_FILE(File) do {} while (0)
283 # define DESTROY_FILE(File) do {} while (0)
285 #endif /* EFL_HAVE_THREADS */
287 /* cache. i don't expect this to ever be large, so arrays will do */
288 static int eet_writers_num = 0;
289 static int eet_writers_alloc = 0;
290 static Eet_File **eet_writers = NULL;
291 static int eet_readers_num = 0;
292 static int eet_readers_alloc = 0;
293 static Eet_File **eet_readers = NULL;
294 static int eet_init_count = 0;
296 /* log domain variable */
297 int _eet_log_dom_global = -1;
299 /* Check to see its' an eet file pointer */
301 eet_check_pointer(const Eet_File *ef)
303 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
307 } /* eet_check_pointer */
310 eet_check_header(const Eet_File *ef)
315 if (!ef->header->directory)
319 } /* eet_check_header */
322 eet_test_close(int test,
327 ef->delete_me_now = 1;
328 eet_internal_close(ef, EINA_TRUE);
332 } /* eet_test_close */
334 /* find an eet file in the currently in use cache */
336 eet_cache_find(const char *path,
343 for (i = 0; i < cache_num; i++)
345 /* if matches real path - return it */
346 if (eet_string_match(cache[i]->path, path))
347 if (!cache[i]->delete_me_now)
354 } /* eet_cache_find */
356 /* add to end of cache */
357 /* this should only be called when the cache lock is already held */
359 eet_cache_add(Eet_File *ef,
364 Eet_File **new_cache;
368 new_cache_num = *cache_num;
369 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
371 Eet_File *del_ef = NULL;
375 for (i = 0; i < new_cache_num; i++)
377 if (new_cache[i]->references == 0)
379 del_ef = new_cache[i];
386 del_ef->delete_me_now = 1;
387 eet_internal_close(del_ef, EINA_TRUE);
392 new_cache_num = *cache_num;
393 new_cache_alloc = *cache_alloc;
395 if (new_cache_num > new_cache_alloc)
397 new_cache_alloc += 16;
398 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
401 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
406 new_cache[new_cache_num - 1] = ef;
408 *cache_num = new_cache_num;
409 *cache_alloc = new_cache_alloc;
410 } /* eet_cache_add */
412 /* delete from cache */
413 /* this should only be called when the cache lock is already held */
415 eet_cache_del(Eet_File *ef,
420 Eet_File **new_cache;
421 int new_cache_num, new_cache_alloc;
425 new_cache_num = *cache_num;
426 new_cache_alloc = *cache_alloc;
427 if (new_cache_num <= 0)
430 for (i = 0; i < new_cache_num; i++)
432 if (new_cache[i] == ef)
436 if (i >= new_cache_num)
440 for (j = i; j < new_cache_num; j++)
441 new_cache[j] = new_cache[j + 1];
443 if (new_cache_num <= (new_cache_alloc - 16))
445 new_cache_alloc -= 16;
446 if (new_cache_num > 0)
448 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
451 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
463 *cache_num = new_cache_num;
464 *cache_alloc = new_cache_alloc;
465 } /* eet_cache_del */
467 /* internal string match. null friendly, catches same ptr */
469 eet_string_match(const char *s1,
472 /* both null- no match */
479 return (!strcmp(s1, s2));
480 } /* eet_string_match */
482 /* flush out writes to a v2 eet file */
484 eet_flush2(Eet_File *ef)
488 Eet_Error error = EET_ERROR_NONE;
489 int head[EET_FILE2_HEADER_COUNT];
490 int num_directory_entries = 0;
491 int num_dictionary_entries = 0;
492 int bytes_directory_entries = 0;
493 int bytes_dictionary_entries = 0;
494 int bytes_strings = 0;
496 int strings_offset = 0;
501 if (eet_check_pointer(ef))
502 return EET_ERROR_BAD_OBJECT;
504 if (eet_check_header(ef))
505 return EET_ERROR_EMPTY;
507 if (!ef->writes_pending)
508 return EET_ERROR_NONE;
510 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
511 || (ef->mode == EET_FILE_MODE_WRITE))
515 /* opening for write - delete old copy of file right away */
517 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
518 fp = fdopen(fd, "wb");
520 return EET_ERROR_NOT_WRITABLE;
522 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
525 return EET_ERROR_NOT_WRITABLE;
527 /* calculate string base offset and data base offset */
528 num = (1 << ef->header->directory->size);
529 for (i = 0; i < num; ++i)
531 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
533 num_directory_entries++;
534 bytes_strings += strlen(efn->name) + 1;
539 num_dictionary_entries = ef->ed->count;
541 for (i = 0; i < num_dictionary_entries; ++i)
542 bytes_strings += ef->ed->all[i].len;
545 /* calculate section bytes size */
546 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
547 num_directory_entries + EET_FILE2_HEADER_SIZE;
548 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
549 num_dictionary_entries;
551 /* calculate per entry offset */
552 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
553 data_offset = bytes_directory_entries + bytes_dictionary_entries +
556 for (i = 0; i < num; ++i)
558 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
560 efn->offset = data_offset;
561 data_offset += efn->size;
563 efn->name_offset = strings_offset;
564 strings_offset += efn->name_size;
568 /* calculate dictionary strings offset */
570 ef->ed->offset = strings_offset;
572 /* go thru and write the header */
573 head[0] = (int)htonl((unsigned int)EET_MAGIC_FILE2);
574 head[1] = (int)htonl((unsigned int)num_directory_entries);
575 head[2] = (int)htonl((unsigned int)num_dictionary_entries);
577 fseek(fp, 0, SEEK_SET);
578 if (fwrite(head, sizeof (head), 1, fp) != 1)
581 /* write directories entry */
582 for (i = 0; i < num; i++)
584 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
587 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
589 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
591 ibuf[0] = (int)htonl((unsigned int)efn->offset);
592 ibuf[1] = (int)htonl((unsigned int)efn->size);
593 ibuf[2] = (int)htonl((unsigned int)efn->data_size);
594 ibuf[3] = (int)htonl((unsigned int)efn->name_offset);
595 ibuf[4] = (int)htonl((unsigned int)efn->name_size);
596 ibuf[5] = (int)htonl((unsigned int)flag);
598 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
603 /* write dictionnary */
606 int offset = strings_offset;
608 for (j = 0; j < ef->ed->count; ++j)
610 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
612 sbuf[0] = (int)htonl((unsigned int)ef->ed->all[j].hash);
613 sbuf[1] = (int)htonl((unsigned int)offset);
614 sbuf[2] = (int)htonl((unsigned int)ef->ed->all[j].len);
615 sbuf[3] = (int)htonl((unsigned int)ef->ed->all[j].prev);
616 sbuf[4] = (int)htonl((unsigned int)ef->ed->all[j].next);
618 offset += ef->ed->all[j].len;
620 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
625 /* write directories name */
626 for (i = 0; i < num; i++)
628 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
630 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
637 for (j = 0; j < ef->ed->count; ++j)
639 if (ef->ed->all[j].str)
641 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
644 else if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, fp) != 1)
649 for (i = 0; i < num; i++)
651 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
653 if (fwrite(efn->data, efn->size, 1, fp) != 1)
658 /* flush all write to the file. */
660 // this is going to really cause trouble. if ANYTHING this needs to go into a
661 // thread spawned off - but even then...
662 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
663 // manual pages at eachother, but ext4 broke behavior that has been in place
664 // for decades and that 1000's of apps rely on daily - that is that one operation
665 // to disk is committed to disk BEFORE following operations, so the fs retains
666 // a consistent state
667 // fsync(fileno(fp));
669 /* append signature if required */
672 error = eet_identity_sign(fp, ef->key);
673 if (error != EET_ERROR_NONE)
677 /* no more writes pending */
678 ef->writes_pending = 0;
682 return EET_ERROR_NONE;
689 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
691 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
693 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
695 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
697 default: error = EET_ERROR_WRITE_ERROR; break;
709 if (++eet_init_count != 1)
710 return eet_init_count;
714 fprintf(stderr, "Eet: Eina init failed");
715 return --eet_init_count;
718 _eet_log_dom_global = eina_log_domain_register("eet", EET_DEFAULT_LOG_COLOR);
719 if (_eet_log_dom_global < 0)
721 EINA_LOG_ERR("Eet Can not create a general log domain.");
725 if (!eet_node_init())
727 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
728 goto unregister_log_domain;
732 /* Before the library can be used, it must initialize itself if needed. */
733 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
735 gcry_check_version(NULL);
736 /* Disable warning messages about problems with the secure memory subsystem.
737 This command should be run right after gcry_check_version. */
738 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
739 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
740 enabling the use of secure memory. It also drops all extra privileges the
741 process has (i.e. if it is run as setuid (root)). If the argument nbytes
742 is 0, secure memory will be disabled. The minimum amount of secure memory
743 allocated is currently 16384 bytes; you may thus use a value of 1 to
744 request that default size. */
746 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
748 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
751 # ifdef EFL_HAVE_POSIX_THREADS
752 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
754 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
756 # endif /* ifdef EFL_HAVE_POSIX_THREADS */
757 if (gnutls_global_init())
760 #endif /* ifdef HAVE_GNUTLS */
762 ERR_load_crypto_strings();
763 OpenSSL_add_all_algorithms();
764 #endif /* ifdef HAVE_OPENSSL */
766 return eet_init_count;
772 unregister_log_domain:
773 eina_log_domain_unregister(_eet_log_dom_global);
774 _eet_log_dom_global = -1;
777 return --eet_init_count;
783 if (--eet_init_count != 0)
784 return eet_init_count;
789 gnutls_global_deinit();
790 #endif /* ifdef HAVE_GNUTLS */
794 #endif /* ifdef HAVE_OPENSSL */
795 eina_log_domain_unregister(_eet_log_dom_global);
796 _eet_log_dom_global = -1;
799 return eet_init_count;
803 eet_sync(Eet_File *ef)
807 if (eet_check_pointer(ef))
808 return EET_ERROR_BAD_OBJECT;
810 if ((ef->mode != EET_FILE_MODE_WRITE) &&
811 (ef->mode != EET_FILE_MODE_READ_WRITE))
812 return EET_ERROR_NOT_WRITABLE;
814 if (!ef->writes_pending)
815 return EET_ERROR_NONE;
819 ret = eet_flush2(ef);
832 * We need to compute the list of eet file to close separately from the cache,
833 * due to eet_close removing them from the cache after each call.
836 for (i = 0; i < eet_writers_num; i++)
838 if (eet_writers[i]->references <= 0)
842 for (i = 0; i < eet_readers_num; i++)
844 if (eet_readers[i]->references <= 0)
850 Eet_File **closelist = NULL;
852 closelist = alloca(num * sizeof(Eet_File *));
854 for (i = 0; i < eet_writers_num; i++)
856 if (eet_writers[i]->references <= 0)
858 closelist[num] = eet_writers[i];
859 eet_writers[i]->delete_me_now = 1;
864 for (i = 0; i < eet_readers_num; i++)
866 if (eet_readers[i]->references <= 0)
868 closelist[num] = eet_readers[i];
869 eet_readers[i]->delete_me_now = 1;
874 for (i = 0; i < num; i++)
876 eet_internal_close(closelist[i], EINA_TRUE);
881 } /* eet_clearcache */
883 /* FIXME: MMAP race condition in READ_WRITE_MODE */
885 eet_internal_read2(Eet_File *ef)
887 const int *data = (const int *)ef->data;
888 const char *start = (const char *)ef->data;
890 int num_directory_entries;
891 int bytes_directory_entries;
892 int num_dictionary_entries;
893 int bytes_dictionary_entries;
894 int signature_base_offset;
898 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
903 #define GET_INT(Value, Pointer, Index)\
905 Value = ntohl(*Pointer);\
907 Index += sizeof(int);\
910 /* get entries count and byte count */
911 GET_INT(num_directory_entries, data, idx);
912 /* get dictionary count and byte count */
913 GET_INT(num_dictionary_entries, data, idx);
915 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
916 num_directory_entries + EET_FILE2_HEADER_SIZE;
917 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
918 num_dictionary_entries;
920 /* we can't have <= 0 values here - invalid */
921 if (eet_test_close((num_directory_entries <= 0), ef))
924 /* we can't have more bytes directory and bytes in dictionaries than the size of the file */
925 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
929 /* allocate header */
930 ef->header = calloc(1, sizeof(Eet_File_Header));
931 if (eet_test_close(!ef->header, ef))
934 ef->header->magic = EET_MAGIC_FILE_HEADER;
936 /* allocate directory block in ram */
937 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
938 if (eet_test_close(!ef->header->directory, ef))
941 /* 8 bit hash table (256 buckets) */
942 ef->header->directory->size = 8;
943 /* allocate base hash table */
944 ef->header->directory->nodes =
945 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
946 if (eet_test_close(!ef->header->directory->nodes, ef))
949 signature_base_offset = 0;
951 /* actually read the directory block - all of it, into ram */
952 for (i = 0; i < num_directory_entries; ++i)
961 /* out directory block is inconsistent - we have oveerun our */
962 /* dynamic block buffer before we finished scanning dir entries */
963 efn = malloc(sizeof(Eet_File_Node));
964 if (eet_test_close(!efn, ef))
966 if (efn) free(efn); /* yes i know - we only get here if
967 * efn is null/0 -> trying to shut up
968 * warning tools like cppcheck */
972 /* get entrie header */
973 GET_INT(efn->offset, data, idx);
974 GET_INT(efn->size, data, idx);
975 GET_INT(efn->data_size, data, idx);
976 GET_INT(name_offset, data, idx);
977 GET_INT(name_size, data, idx);
978 GET_INT(flag, data, idx);
980 efn->compression = flag & 0x1 ? 1 : 0;
981 efn->ciphered = flag & 0x2 ? 1 : 0;
982 efn->alias = flag & 0x4 ? 1 : 0;
984 #define EFN_TEST(Test, Ef, Efn)\
985 if (eet_test_close(Test, Ef))\
991 /* check data pointer position */
992 EFN_TEST(!((efn->size > 0)
993 && (efn->offset + efn->size <= ef->data_size)
994 && (efn->offset > bytes_dictionary_entries +
995 bytes_directory_entries)), ef, efn);
997 /* check name position */
998 EFN_TEST(!((name_size > 0)
999 && (name_offset + name_size < ef->data_size)
1000 && (name_offset >= bytes_dictionary_entries +
1001 bytes_directory_entries)), ef, efn);
1003 name = start + name_offset;
1005 /* check '\0' at the end of name string */
1006 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
1009 efn->name = (char *)name;
1010 efn->name_size = name_size;
1012 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1013 efn->next = ef->header->directory->nodes[hash];
1014 ef->header->directory->nodes[hash] = efn;
1016 /* read-only mode, so currently we have no data loaded */
1017 if (ef->mode == EET_FILE_MODE_READ)
1018 efn->data = NULL; /* read-write mode - read everything into ram */
1021 efn->data = malloc(efn->size);
1023 memcpy(efn->data, ef->data + efn->offset, efn->size);
1026 /* compute the possible position of a signature */
1027 if (signature_base_offset < efn->offset + efn->size)
1028 signature_base_offset = efn->offset + efn->size;
1033 if (num_dictionary_entries)
1035 const int *dico = (const int *)ef->data +
1036 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1037 EET_FILE2_HEADER_COUNT;
1040 if (eet_test_close((num_dictionary_entries *
1041 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1042 (bytes_dictionary_entries + bytes_directory_entries),
1046 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1047 if (eet_test_close(!ef->ed, ef))
1050 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1051 if (eet_test_close(!ef->ed->all, ef))
1054 ef->ed->count = num_dictionary_entries;
1055 ef->ed->total = num_dictionary_entries;
1056 ef->ed->start = start + bytes_dictionary_entries +
1057 bytes_directory_entries;
1058 ef->ed->end = ef->ed->start;
1060 for (j = 0; j < ef->ed->count; ++j)
1065 GET_INT(hash, dico, idx);
1066 GET_INT(offset, dico, idx);
1067 GET_INT(ef->ed->all[j].len, dico, idx);
1068 GET_INT(ef->ed->all[j].prev, dico, idx);
1069 GET_INT(ef->ed->all[j].next, dico, idx);
1071 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1072 So stick to int and check the value. */
1073 if (eet_test_close(hash & 0xFFFFFF00, ef))
1076 /* Check string position */
1077 if (eet_test_close(!((ef->ed->all[j].len > 0)
1079 (bytes_dictionary_entries +
1080 bytes_directory_entries))
1081 && (offset + ef->ed->all[j].len <
1082 ef->data_size)), ef))
1085 ef->ed->all[j].mmap = start + offset;
1086 ef->ed->all[j].str = NULL;
1088 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
1089 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
1091 /* Check '\0' at the end of the string */
1092 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] !=
1096 ef->ed->all[j].hash = hash;
1097 if (ef->ed->all[j].prev == -1)
1098 ef->ed->hash[hash] = j;
1100 /* compute the possible position of a signature */
1101 if (signature_base_offset < offset + ef->ed->all[j].len)
1102 signature_base_offset = offset + ef->ed->all[j].len;
1106 /* Check if the file is signed */
1107 ef->x509_der = NULL;
1108 ef->x509_length = 0;
1109 ef->signature = NULL;
1110 ef->signature_length = 0;
1112 if (signature_base_offset < ef->data_size)
1114 #ifdef HAVE_SIGNATURE
1115 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1116 signature_base_offset;
1117 ef->x509_der = eet_identity_check(ef->data,
1118 signature_base_offset,
1122 ef->data_size - signature_base_offset,
1124 &ef->signature_length,
1127 if (eet_test_close(!ef->x509_der, ef))
1130 #else /* ifdef HAVE_SIGNATURE */
1132 "This file could be signed but you didn't compile the necessary code to check the signature.");
1133 #endif /* ifdef HAVE_SIGNATURE */
1137 } /* eet_internal_read2 */
1139 #if EET_OLD_EET_FILE_FORMAT
1141 eet_internal_read1(Eet_File *ef)
1143 const unsigned char *dyn_buf = NULL;
1144 const unsigned char *p = NULL;
1151 "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.",
1154 /* build header table if read mode */
1157 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1160 #define EXTRACT_INT(Value, Pointer, Index)\
1163 memcpy(&tmp, Pointer + Index, sizeof(int));\
1164 Value = ntohl(tmp);\
1165 Index += sizeof(int);\
1168 /* get entries count and byte count */
1169 EXTRACT_INT(num_entries, ef->data, idx);
1170 EXTRACT_INT(byte_entries, ef->data, idx);
1172 /* we can't have <= 0 values here - invalid */
1173 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1176 /* we can't have more entires than minimum bytes for those! invalid! */
1177 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1180 /* check we will not outrun the file limit */
1181 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1185 /* allocate header */
1186 ef->header = calloc(1, sizeof(Eet_File_Header));
1187 if (eet_test_close(!ef->header, ef))
1190 ef->header->magic = EET_MAGIC_FILE_HEADER;
1192 /* allocate directory block in ram */
1193 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1194 if (eet_test_close(!ef->header->directory, ef))
1197 /* 8 bit hash table (256 buckets) */
1198 ef->header->directory->size = 8;
1199 /* allocate base hash table */
1200 ef->header->directory->nodes =
1201 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1202 if (eet_test_close(!ef->header->directory->nodes, ef))
1205 /* actually read the directory block - all of it, into ram */
1206 dyn_buf = ef->data + idx;
1208 /* parse directory block */
1211 for (i = 0; i < num_entries; i++)
1220 #define HEADER_SIZE (sizeof(int) * 5)
1222 /* out directory block is inconsistent - we have oveerun our */
1223 /* dynamic block buffer before we finished scanning dir entries */
1224 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1227 /* allocate all the ram needed for this stored node accounting */
1228 efn = malloc (sizeof(Eet_File_Node));
1229 if (eet_test_close(!efn, ef))
1231 if (efn) free(efn); /* yes i know - we only get here if
1232 * efn is null/0 -> trying to shut up
1233 * warning tools like cppcheck */
1237 /* get entrie header */
1238 EXTRACT_INT(efn->offset, p, indexn);
1239 EXTRACT_INT(efn->compression, p, indexn);
1240 EXTRACT_INT(efn->size, p, indexn);
1241 EXTRACT_INT(efn->data_size, p, indexn);
1242 EXTRACT_INT(name_size, p, indexn);
1244 efn->name_size = name_size;
1249 if (eet_test_close(efn->size <= 0, ef))
1255 /* invalid name_size */
1256 if (eet_test_close(name_size <= 0, ef))
1262 /* reading name would mean falling off end of dyn_buf - invalid */
1263 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1269 /* This code is useless if we dont want backward compatibility */
1271 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1274 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1278 efn->name = malloc(sizeof(char) * name_size + 1);
1279 if (eet_test_close(!efn->name, ef))
1285 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1286 efn->name[name_size] = 0;
1289 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1294 /* The only really useful peace of code for efn->name (no backward compatibility) */
1295 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1297 /* get hash bucket it should go in */
1298 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1299 efn->next = ef->header->directory->nodes[hash];
1300 ef->header->directory->nodes[hash] = efn;
1302 /* read-only mode, so currently we have no data loaded */
1303 if (ef->mode == EET_FILE_MODE_READ)
1304 efn->data = NULL; /* read-write mode - read everything into ram */
1307 data = malloc(efn->size);
1309 memcpy(data, ef->data + efn->offset, efn->size);
1315 p += HEADER_SIZE + name_size;
1318 } /* eet_internal_read1 */
1320 #endif /* if EET_OLD_EET_FILE_FORMAT */
1323 * this should only be called when the cache lock is already held
1324 * (We could drop this restriction if we add a parameter to eet_test_close
1325 * that indicates if the lock is held or not. For now it is easiest
1326 * to just require that it is always held.)
1329 eet_internal_read(Eet_File *ef)
1331 const int *data = (const int *)ef->data;
1333 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1336 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1339 switch (ntohl(*data))
1341 #if EET_OLD_EET_FILE_FORMAT
1342 case EET_MAGIC_FILE:
1343 return eet_internal_read1(ef);
1345 #endif /* if EET_OLD_EET_FILE_FORMAT */
1346 case EET_MAGIC_FILE2:
1347 return eet_internal_read2(ef);
1350 ef->delete_me_now = 1;
1351 eet_internal_close(ef, EINA_TRUE);
1356 } /* eet_internal_read */
1359 eet_internal_close(Eet_File *ef,
1364 /* check to see its' an eet file pointer */
1365 if (eet_check_pointer(ef))
1366 return EET_ERROR_BAD_OBJECT;
1373 /* if its still referenced - dont go any further */
1374 if (ef->references > 0)
1375 goto on_error; /* flush any writes */
1377 err = eet_flush2(ef);
1379 eet_identity_unref(ef->key);
1382 /* if not urgent to delete it - dont free it - leave it in cache */
1383 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1386 /* remove from cache */
1387 if (ef->mode == EET_FILE_MODE_READ)
1388 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1389 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1393 mode == EET_FILE_MODE_READ_WRITE))
1394 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1396 /* we can unlock the cache now */
1405 if (ef->header->directory)
1407 if (ef->header->directory->nodes)
1411 num = (1 << ef->header->directory->size);
1412 for (i = 0; i < num; i++)
1416 while ((efn = ef->header->directory->nodes[i]))
1421 ef->header->directory->nodes[i] = efn->next;
1429 free(ef->header->directory->nodes);
1432 free(ef->header->directory);
1438 eet_dictionary_free(ef->ed);
1444 munmap((void *)ef->data, ef->data_size);
1449 /* zero out ram for struct - caution tactic against stale memory use */
1450 memset(ef, 0, sizeof(Eet_File));
1460 return EET_ERROR_NONE;
1461 } /* eet_internal_close */
1464 eet_memopen_read(const void *data,
1469 if (!data || size == 0)
1472 ef = malloc (sizeof (Eet_File));
1480 ef->magic = EET_MAGIC_FILE;
1482 ef->mode = EET_FILE_MODE_READ;
1485 ef->delete_me_now = 1;
1488 ef->data_size = size;
1490 ef->sha1_length = 0;
1492 /* eet_internal_read expects the cache lock to be held when it is called */
1494 ef = eet_internal_read(ef);
1497 } /* eet_memopen_read */
1500 eet_open(const char *file,
1506 struct stat file_stat;
1511 /* find the current file handle in cache*/
1514 if (mode == EET_FILE_MODE_READ)
1516 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1521 ef->delete_me_now = 1;
1522 eet_internal_close(ef, EINA_TRUE);
1525 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1527 else if ((mode == EET_FILE_MODE_WRITE) ||
1528 (mode == EET_FILE_MODE_READ_WRITE))
1530 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1533 ef->delete_me_now = 1;
1535 eet_internal_close(ef, EINA_TRUE);
1538 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1541 /* try open the file based on mode */
1542 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1544 /* Prevent garbage in futur comparison. */
1545 file_stat.st_mtime = 0;
1547 fp = fopen(file, "rb");
1551 if (fstat(fileno(fp), &file_stat))
1558 if (file_stat.st_size < ((int)sizeof(int) * 3))
1566 if (!fp && mode == EET_FILE_MODE_READ)
1571 if (mode != EET_FILE_MODE_WRITE)
1574 memset(&file_stat, 0, sizeof(file_stat));
1581 ((file_stat.st_mtime != ef->mtime) ||
1582 (file_stat.st_size != ef->data_size)))
1584 ef->delete_me_now = 1;
1586 eet_internal_close(ef, EINA_TRUE);
1592 /* reference it up and return it */
1601 file_len = strlen(file) + 1;
1603 /* Allocate struct for eet file and have it zero'd out */
1604 ef = malloc(sizeof(Eet_File) + file_len);
1608 /* fill some of the members */
1612 ef->path = ((char *)ef) + sizeof(Eet_File);
1613 memcpy(ef->path, file, file_len);
1614 ef->magic = EET_MAGIC_FILE;
1618 ef->mtime = file_stat.st_mtime;
1619 ef->writes_pending = 0;
1620 ef->delete_me_now = 0;
1624 ef->sha1_length = 0;
1626 ef->ed = (mode == EET_FILE_MODE_WRITE)
1627 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1628 eet_dictionary_add() : NULL;
1631 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1634 /* if we can't open - bail out */
1635 if (eet_test_close(!ef->readfp, ef))
1638 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1639 /* if we opened for read or read-write */
1640 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1642 ef->data_size = file_stat.st_size;
1643 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1644 MAP_SHARED, fileno(ef->readfp), 0);
1645 if (eet_test_close((ef->data == MAP_FAILED), ef))
1648 ef = eet_internal_read(ef);
1655 if (ef->references == 1)
1657 if (ef->mode == EET_FILE_MODE_READ)
1658 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1660 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1661 (ef->mode == EET_FILE_MODE_READ_WRITE))
1662 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1674 eet_mode_get(Eet_File *ef)
1676 /* check to see its' an eet file pointer */
1677 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1678 return EET_FILE_MODE_INVALID;
1681 } /* eet_mode_get */
1684 eet_identity_x509(Eet_File *ef,
1691 *der_length = ef->x509_length;
1693 return ef->x509_der;
1694 } /* eet_identity_x509 */
1697 eet_identity_signature(Eet_File *ef,
1698 int *signature_length)
1703 if (signature_length)
1704 *signature_length = ef->signature_length;
1706 return ef->signature;
1707 } /* eet_identity_signature */
1710 eet_identity_sha1(Eet_File *ef,
1714 ef->sha1 = eet_identity_compute_sha1(ef->data,
1719 *sha1_length = ef->sha1_length;
1722 } /* eet_identity_sha1 */
1725 eet_identity_set(Eet_File *ef,
1728 Eet_Key *tmp = ef->key;
1731 return EET_ERROR_BAD_OBJECT;
1734 eet_identity_ref(ef->key);
1735 eet_identity_unref(tmp);
1737 /* flags that writes are pending */
1738 ef->writes_pending = 1;
1740 return EET_ERROR_NONE;
1741 } /* eet_identity_set */
1744 eet_close(Eet_File *ef)
1746 return eet_internal_close(ef, EINA_FALSE);
1750 eet_read_cipher(Eet_File *ef,
1753 const char *cipher_key)
1762 /* check to see its' an eet file pointer */
1763 if (eet_check_pointer(ef))
1769 if ((ef->mode != EET_FILE_MODE_READ) &&
1770 (ef->mode != EET_FILE_MODE_READ_WRITE))
1773 /* no header, return NULL */
1774 if (eet_check_header(ef))
1779 /* hunt hash bucket */
1780 efn = find_node_by_name(ef, name);
1784 /* get size (uncompressed, if compressed at all) */
1785 size = efn->data_size;
1788 data = malloc(size);
1792 /* uncompressed data */
1793 if (efn->compression == 0)
1795 void *data_deciphered = NULL;
1796 unsigned int data_deciphered_sz = 0;
1797 /* if we already have the data in ram... copy that */
1800 memcpy(data, efn->data, efn->size);
1802 if (!read_data_from_disk(ef, efn, data, size))
1805 if (efn->ciphered && cipher_key)
1807 if (eet_decipher(data, size, cipher_key, strlen(cipher_key),
1808 &data_deciphered, &data_deciphered_sz))
1810 if (data_deciphered)
1811 free(data_deciphered);
1817 data = data_deciphered;
1818 size = data_deciphered_sz;
1821 /* compressed data */
1825 void *data_deciphered = NULL;
1826 unsigned int data_deciphered_sz = 0;
1828 int compr_size = efn->size;
1831 /* if we already have the data in ram... copy that */
1833 tmp_data = efn->data;
1836 tmp_data = malloc(compr_size);
1842 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1849 if (efn->ciphered && cipher_key)
1851 if (eet_decipher(tmp_data, compr_size, cipher_key,
1852 strlen(cipher_key), &data_deciphered,
1853 &data_deciphered_sz))
1858 if (data_deciphered)
1859 free(data_deciphered);
1865 tmp_data = data_deciphered;
1866 compr_size = data_deciphered_sz;
1871 if (uncompress((Bytef *)data, &dlen,
1872 tmp_data, (uLongf)compr_size))
1886 if (data[size - 1] != '\0')
1889 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1896 /* fill in return values */
1906 } /* eet_read_cipher */
1909 eet_read(Eet_File *ef,
1913 return eet_read_cipher(ef, name, size_ret, NULL);
1917 eet_read_direct(Eet_File *ef,
1922 const char *data = NULL;
1928 /* check to see its' an eet file pointer */
1929 if (eet_check_pointer(ef))
1935 if ((ef->mode != EET_FILE_MODE_READ) &&
1936 (ef->mode != EET_FILE_MODE_READ_WRITE))
1939 /* no header, return NULL */
1940 if (eet_check_header(ef))
1945 /* hunt hash bucket */
1946 efn = find_node_by_name(ef, name);
1950 if (efn->offset < 0 && !efn->data)
1953 /* get size (uncompressed, if compressed at all) */
1954 size = efn->data_size;
1958 data = efn->data ? efn->data : ef->data + efn->offset;
1960 /* handle alias case */
1961 if (efn->compression)
1964 int compr_size = efn->size;
1967 tmp = alloca(sizeof (compr_size));
1970 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1971 (uLongf)compr_size))
1974 if (tmp[compr_size - 1] != '\0')
1979 return eet_read_direct(ef, tmp, size_ret);
1985 if (data[size - 1] != '\0')
1990 return eet_read_direct(ef, data, size_ret);
1993 /* uncompressed data */
1994 if (efn->compression == 0
1995 && efn->ciphered == 0)
1996 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
2000 /* fill in return values */
2011 } /* eet_read_direct */
2014 eet_alias(Eet_File *ef,
2016 const char *destination,
2021 Eina_Bool exists_already = EINA_FALSE;
2025 /* check to see its' an eet file pointer */
2026 if (eet_check_pointer(ef))
2029 if ((!name) || (!destination))
2032 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2033 (ef->mode != EET_FILE_MODE_READ_WRITE))
2040 /* allocate header */
2041 ef->header = calloc(1, sizeof(Eet_File_Header));
2045 ef->header->magic = EET_MAGIC_FILE_HEADER;
2046 /* allocate directory block in ram */
2047 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2048 if (!ef->header->directory)
2055 /* 8 bit hash table (256 buckets) */
2056 ef->header->directory->size = 8;
2057 /* allocate base hash table */
2058 ef->header->directory->nodes =
2059 calloc(1, sizeof(Eet_File_Node *) *
2060 (1 << ef->header->directory->size));
2061 if (!ef->header->directory->nodes)
2063 free(ef->header->directory);
2069 /* figure hash bucket */
2070 hash = _eet_hash_gen(name, ef->header->directory->size);
2073 12 + (((strlen(destination) + 1) * 101) / 100)
2074 : strlen(destination) + 1;
2076 data2 = malloc(data_size);
2080 /* if we want to compress */
2085 /* compress the data with max compression */
2086 buflen = (uLongf)data_size;
2087 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2088 (uLong)strlen(destination) + 1,
2089 Z_BEST_COMPRESSION) != Z_OK)
2095 /* record compressed chunk size */
2096 data_size = (int)buflen;
2097 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2100 data_size = strlen(destination) + 1;
2106 data3 = realloc(data2, data_size);
2113 memcpy(data2, destination, data_size);
2115 /* Does this node already exist? */
2116 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2119 if ((efn->name) && (eet_string_match(efn->name, name)))
2124 efn->compression = !!comp;
2125 efn->size = data_size;
2126 efn->data_size = strlen(destination) + 1;
2129 exists_already = EINA_TRUE;
2133 if (!exists_already)
2135 efn = malloc(sizeof(Eet_File_Node));
2142 efn->name = strdup(name);
2143 efn->name_size = strlen(efn->name) + 1;
2146 efn->next = ef->header->directory->nodes[hash];
2147 ef->header->directory->nodes[hash] = efn;
2151 efn->compression = !!comp;
2152 efn->size = data_size;
2153 efn->data_size = strlen(destination) + 1;
2157 /* flags that writes are pending */
2158 ef->writes_pending = 1;
2169 eet_write_cipher(Eet_File *ef,
2174 const char *cipher_key)
2178 int exists_already = 0;
2182 /* check to see its' an eet file pointer */
2183 if (eet_check_pointer(ef))
2186 if ((!name) || (!data) || (size <= 0))
2189 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2190 (ef->mode != EET_FILE_MODE_READ_WRITE))
2197 /* allocate header */
2198 ef->header = calloc(1, sizeof(Eet_File_Header));
2202 ef->header->magic = EET_MAGIC_FILE_HEADER;
2203 /* allocate directory block in ram */
2204 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2205 if (!ef->header->directory)
2212 /* 8 bit hash table (256 buckets) */
2213 ef->header->directory->size = 8;
2214 /* allocate base hash table */
2215 ef->header->directory->nodes =
2216 calloc(1, sizeof(Eet_File_Node *) *
2217 (1 << ef->header->directory->size));
2218 if (!ef->header->directory->nodes)
2220 free(ef->header->directory);
2226 /* figure hash bucket */
2227 hash = _eet_hash_gen(name, ef->header->directory->size);
2229 data_size = comp ? 12 + ((size * 101) / 100) : size;
2231 if (comp || !cipher_key)
2233 data2 = malloc(data_size);
2238 /* if we want to compress */
2243 /* compress the data with max compression */
2244 buflen = (uLongf)data_size;
2245 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2246 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2252 /* record compressed chunk size */
2253 data_size = (int)buflen;
2254 if (data_size < 0 || data_size >= size)
2263 data3 = realloc(data2, data_size);
2271 void *data_ciphered = NULL;
2272 unsigned int data_ciphered_sz = 0;
2275 tmp = comp ? data2 : data;
2276 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2277 &data_ciphered, &data_ciphered_sz))
2282 data2 = data_ciphered;
2283 data_size = data_ciphered_sz;
2284 size = (data_size > size) ? data_size : size;
2289 free(data_ciphered);
2296 memcpy(data2, data, size);
2298 /* Does this node already exist? */
2299 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2302 if ((efn->name) && (eet_string_match(efn->name, name)))
2306 efn->ciphered = cipher_key ? 1 : 0;
2307 efn->compression = !!comp;
2308 efn->size = data_size;
2309 efn->data_size = size;
2316 if (!exists_already)
2318 efn = malloc(sizeof(Eet_File_Node));
2325 efn->name = strdup(name);
2326 efn->name_size = strlen(efn->name) + 1;
2329 efn->next = ef->header->directory->nodes[hash];
2330 ef->header->directory->nodes[hash] = efn;
2333 efn->ciphered = cipher_key ? 1 : 0;
2334 efn->compression = !!comp;
2335 efn->size = data_size;
2336 efn->data_size = size;
2340 /* flags that writes are pending */
2341 ef->writes_pending = 1;
2348 } /* eet_write_cipher */
2351 eet_write(Eet_File *ef,
2357 return eet_write_cipher(ef, name, data, size, comp, NULL);
2361 eet_delete(Eet_File *ef,
2365 Eet_File_Node *pefn;
2367 int exists_already = 0;
2369 /* check to see its' an eet file pointer */
2370 if (eet_check_pointer(ef))
2376 /* deleting keys is only possible in RW or WRITE mode */
2377 if (ef->mode == EET_FILE_MODE_READ)
2380 if (eet_check_header(ef))
2385 /* figure hash bucket */
2386 hash = _eet_hash_gen(name, ef->header->directory->size);
2388 /* Does this node already exist? */
2389 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2391 pefn = efn, efn = efn->next)
2394 if (eet_string_match(efn->name, name))
2400 ef->header->directory->nodes[hash] = efn->next;
2402 pefn->next = efn->next;
2412 /* flags that writes are pending */
2414 ef->writes_pending = 1;
2418 /* update access time */
2419 return exists_already;
2422 EAPI Eet_Dictionary *
2423 eet_dictionary_get(Eet_File *ef)
2425 if (eet_check_pointer(ef))
2429 } /* eet_dictionary_get */
2432 eet_list(Eet_File *ef,
2437 char **list_ret = NULL;
2439 int list_count_alloc = 0;
2442 /* check to see its' an eet file pointer */
2443 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2445 ((ef->mode != EET_FILE_MODE_READ) &&
2446 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2454 if (!strcmp(glob, "*"))
2459 /* loop through all entries */
2460 num = (1 << ef->header->directory->size);
2461 for (i = 0; i < num; i++)
2463 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2465 /* if the entry matches the input glob
2466 * check for * explicitly, because on some systems, * isn't well
2469 if ((!glob) || !fnmatch(glob, efn->name, 0))
2471 /* add it to our list */
2474 /* only realloc in 32 entry chunks */
2475 if (list_count > list_count_alloc)
2477 char **new_list = NULL;
2479 list_count_alloc += 64;
2481 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2489 list_ret = new_list;
2492 /* put pointer of name string in */
2493 list_ret[list_count - 1] = efn->name;
2500 /* return count and list */
2502 *count_ret = list_count;
2516 eet_num_entries(Eet_File *ef)
2518 int i, num, ret = 0;
2521 /* check to see its' an eet file pointer */
2522 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2523 ((ef->mode != EET_FILE_MODE_READ) &&
2524 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2529 /* loop through all entries */
2530 num = (1 << ef->header->directory->size);
2531 for (i = 0; i < num; i++)
2533 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2540 } /* eet_num_entries */
2542 static Eet_File_Node *
2543 find_node_by_name(Eet_File *ef,
2549 /* get hash bucket this should be in */
2550 hash = _eet_hash_gen(name, ef->header->directory->size);
2552 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2554 if (eet_string_match(efn->name, name))
2559 } /* find_node_by_name */
2562 read_data_from_disk(Eet_File *ef,
2567 if (efn->offset < 0)
2572 if ((efn->offset + len) > ef->data_size)
2575 memcpy(buf, ef->data + efn->offset, len);
2582 /* seek to data location */
2583 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2587 len = fread(buf, len, 1, ef->readfp);
2591 } /* read_data_from_disk */