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;
770 unregister_log_domain:
771 eina_log_domain_unregister(_eet_log_dom_global);
772 _eet_log_dom_global = -1;
775 return --eet_init_count;
781 if (--eet_init_count != 0)
782 return eet_init_count;
787 gnutls_global_deinit();
788 #endif /* ifdef HAVE_GNUTLS */
792 #endif /* ifdef HAVE_OPENSSL */
793 eina_log_domain_unregister(_eet_log_dom_global);
794 _eet_log_dom_global = -1;
797 return eet_init_count;
801 eet_sync(Eet_File *ef)
805 if (eet_check_pointer(ef))
806 return EET_ERROR_BAD_OBJECT;
808 if ((ef->mode != EET_FILE_MODE_WRITE) &&
809 (ef->mode != EET_FILE_MODE_READ_WRITE))
810 return EET_ERROR_NOT_WRITABLE;
812 if (!ef->writes_pending)
813 return EET_ERROR_NONE;
817 ret = eet_flush2(ef);
830 * We need to compute the list of eet file to close separately from the cache,
831 * due to eet_close removing them from the cache after each call.
834 for (i = 0; i < eet_writers_num; i++)
836 if (eet_writers[i]->references <= 0)
840 for (i = 0; i < eet_readers_num; i++)
842 if (eet_readers[i]->references <= 0)
848 Eet_File **closelist = NULL;
850 closelist = alloca(num * sizeof(Eet_File *));
852 for (i = 0; i < eet_writers_num; i++)
854 if (eet_writers[i]->references <= 0)
856 closelist[num] = eet_writers[i];
857 eet_writers[i]->delete_me_now = 1;
862 for (i = 0; i < eet_readers_num; i++)
864 if (eet_readers[i]->references <= 0)
866 closelist[num] = eet_readers[i];
867 eet_readers[i]->delete_me_now = 1;
872 for (i = 0; i < num; i++)
874 eet_internal_close(closelist[i], EINA_TRUE);
879 } /* eet_clearcache */
881 /* FIXME: MMAP race condition in READ_WRITE_MODE */
883 eet_internal_read2(Eet_File *ef)
885 const int *data = (const int *)ef->data;
886 const char *start = (const char *)ef->data;
888 int num_directory_entries;
889 int bytes_directory_entries;
890 int num_dictionary_entries;
891 int bytes_dictionary_entries;
892 int signature_base_offset;
896 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
901 #define GET_INT(Value, Pointer, Index)\
903 Value = ntohl(*Pointer);\
905 Index += sizeof(int);\
908 /* get entries count and byte count */
909 GET_INT(num_directory_entries, data, idx);
910 /* get dictionary count and byte count */
911 GET_INT(num_dictionary_entries, data, idx);
913 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
914 num_directory_entries + EET_FILE2_HEADER_SIZE;
915 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
916 num_dictionary_entries;
918 /* we cant have <= 0 values here - invalid */
919 if (eet_test_close((num_directory_entries <= 0), ef))
922 /* we cant have more bytes directory and bytes in dictionaries than the size of the file */
923 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
927 /* allocate header */
928 ef->header = calloc(1, sizeof(Eet_File_Header));
929 if (eet_test_close(!ef->header, ef))
932 ef->header->magic = EET_MAGIC_FILE_HEADER;
934 /* allocate directory block in ram */
935 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
936 if (eet_test_close(!ef->header->directory, ef))
939 /* 8 bit hash table (256 buckets) */
940 ef->header->directory->size = 8;
941 /* allocate base hash table */
942 ef->header->directory->nodes =
943 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
944 if (eet_test_close(!ef->header->directory->nodes, ef))
947 signature_base_offset = 0;
949 /* actually read the directory block - all of it, into ram */
950 for (i = 0; i < num_directory_entries; ++i)
959 /* out directory block is inconsistent - we have oveerun our */
960 /* dynamic block buffer before we finished scanning dir entries */
961 efn = malloc (sizeof(Eet_File_Node));
962 if (eet_test_close(!efn, ef))
965 /* get entrie header */
966 GET_INT(efn->offset, data, idx);
967 GET_INT(efn->size, data, idx);
968 GET_INT(efn->data_size, data, idx);
969 GET_INT(name_offset, data, idx);
970 GET_INT(name_size, data, idx);
971 GET_INT(flag, data, idx);
973 efn->compression = flag & 0x1 ? 1 : 0;
974 efn->ciphered = flag & 0x2 ? 1 : 0;
975 efn->alias = flag & 0x4 ? 1 : 0;
977 #define EFN_TEST(Test, Ef, Efn)\
978 if (eet_test_close(Test, Ef))\
984 /* check data pointer position */
985 EFN_TEST(!((efn->size > 0)
986 && (efn->offset + efn->size <= ef->data_size)
987 && (efn->offset > bytes_dictionary_entries +
988 bytes_directory_entries)), ef, efn);
990 /* check name position */
991 EFN_TEST(!((name_size > 0)
992 && (name_offset + name_size < ef->data_size)
993 && (name_offset >= bytes_dictionary_entries +
994 bytes_directory_entries)), ef, efn);
996 name = start + name_offset;
998 /* check '\0' at the end of name string */
999 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
1002 efn->name = (char *)name;
1003 efn->name_size = name_size;
1005 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1006 efn->next = ef->header->directory->nodes[hash];
1007 ef->header->directory->nodes[hash] = efn;
1009 /* read-only mode, so currently we have no data loaded */
1010 if (ef->mode == EET_FILE_MODE_READ)
1011 efn->data = NULL; /* read-write mode - read everything into ram */
1014 efn->data = malloc(efn->size);
1016 memcpy(efn->data, ef->data + efn->offset, efn->size);
1019 /* compute the possible position of a signature */
1020 if (signature_base_offset < efn->offset + efn->size)
1021 signature_base_offset = efn->offset + efn->size;
1026 if (num_dictionary_entries)
1028 const int *dico = (const int *)ef->data +
1029 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1030 EET_FILE2_HEADER_COUNT;
1033 if (eet_test_close((num_dictionary_entries *
1034 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1035 (bytes_dictionary_entries + bytes_directory_entries),
1039 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1040 if (eet_test_close(!ef->ed, ef))
1043 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1044 if (eet_test_close(!ef->ed->all, ef))
1047 ef->ed->count = num_dictionary_entries;
1048 ef->ed->total = num_dictionary_entries;
1049 ef->ed->start = start + bytes_dictionary_entries +
1050 bytes_directory_entries;
1051 ef->ed->end = ef->ed->start;
1053 for (j = 0; j < ef->ed->count; ++j)
1058 GET_INT(hash, dico, idx);
1059 GET_INT(offset, dico, idx);
1060 GET_INT(ef->ed->all[j].len, dico, idx);
1061 GET_INT(ef->ed->all[j].prev, dico, idx);
1062 GET_INT(ef->ed->all[j].next, dico, idx);
1064 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1065 So stick to int and check the value. */
1066 if (eet_test_close(hash & 0xFFFFFF00, ef))
1069 /* Check string position */
1070 if (eet_test_close(!((ef->ed->all[j].len > 0)
1072 (bytes_dictionary_entries +
1073 bytes_directory_entries))
1074 && (offset + ef->ed->all[j].len <
1075 ef->data_size)), ef))
1078 ef->ed->all[j].mmap = start + offset;
1079 ef->ed->all[j].str = NULL;
1081 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
1082 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
1084 /* Check '\0' at the end of the string */
1085 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] !=
1089 ef->ed->all[j].hash = hash;
1090 if (ef->ed->all[j].prev == -1)
1091 ef->ed->hash[hash] = j;
1093 /* compute the possible position of a signature */
1094 if (signature_base_offset < offset + ef->ed->all[j].len)
1095 signature_base_offset = offset + ef->ed->all[j].len;
1099 /* Check if the file is signed */
1100 ef->x509_der = NULL;
1101 ef->x509_length = 0;
1102 ef->signature = NULL;
1103 ef->signature_length = 0;
1105 if (signature_base_offset < ef->data_size)
1107 #ifdef HAVE_SIGNATURE
1108 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1109 signature_base_offset;
1110 ef->x509_der = eet_identity_check(ef->data,
1111 signature_base_offset,
1115 ef->data_size - signature_base_offset,
1117 &ef->signature_length,
1120 if (eet_test_close(ef->x509_der == NULL, ef))
1123 #else /* ifdef HAVE_SIGNATURE */
1125 "This file could be signed but you didn't compile the necessary code to check the signature.");
1126 #endif /* ifdef HAVE_SIGNATURE */
1130 } /* eet_internal_read2 */
1132 #if EET_OLD_EET_FILE_FORMAT
1134 eet_internal_read1(Eet_File *ef)
1136 const unsigned char *dyn_buf = NULL;
1137 const unsigned char *p = NULL;
1144 "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.",
1147 /* build header table if read mode */
1150 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1153 #define EXTRACT_INT(Value, Pointer, Index)\
1156 memcpy(&tmp, Pointer + Index, sizeof(int));\
1157 Value = ntohl(tmp);\
1158 Index += sizeof(int);\
1161 /* get entries count and byte count */
1162 EXTRACT_INT(num_entries, ef->data, idx);
1163 EXTRACT_INT(byte_entries, ef->data, idx);
1165 /* we cant have <= 0 values here - invalid */
1166 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1169 /* we can't have more entires than minimum bytes for those! invalid! */
1170 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1173 /* check we will not outrun the file limit */
1174 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1178 /* allocate header */
1179 ef->header = calloc(1, sizeof(Eet_File_Header));
1180 if (eet_test_close(!ef->header, ef))
1183 ef->header->magic = EET_MAGIC_FILE_HEADER;
1185 /* allocate directory block in ram */
1186 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1187 if (eet_test_close(!ef->header->directory, ef))
1190 /* 8 bit hash table (256 buckets) */
1191 ef->header->directory->size = 8;
1192 /* allocate base hash table */
1193 ef->header->directory->nodes =
1194 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1195 if (eet_test_close(!ef->header->directory->nodes, ef))
1198 /* actually read the directory block - all of it, into ram */
1199 dyn_buf = ef->data + idx;
1201 /* parse directory block */
1204 for (i = 0; i < num_entries; i++)
1213 #define HEADER_SIZE (sizeof(int) * 5)
1215 /* out directory block is inconsistent - we have oveerun our */
1216 /* dynamic block buffer before we finished scanning dir entries */
1217 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1220 /* allocate all the ram needed for this stored node accounting */
1221 efn = malloc (sizeof(Eet_File_Node));
1222 if (eet_test_close(!efn, ef))
1225 /* get entrie header */
1226 EXTRACT_INT(efn->offset, p, indexn);
1227 EXTRACT_INT(efn->compression, p, indexn);
1228 EXTRACT_INT(efn->size, p, indexn);
1229 EXTRACT_INT(efn->data_size, p, indexn);
1230 EXTRACT_INT(name_size, p, indexn);
1232 efn->name_size = name_size;
1237 if (eet_test_close(efn->size <= 0, ef))
1243 /* invalid name_size */
1244 if (eet_test_close(name_size <= 0, ef))
1250 /* reading name would mean falling off end of dyn_buf - invalid */
1251 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1257 /* This code is useless if we dont want backward compatibility */
1259 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1262 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1266 efn->name = malloc(sizeof(char) * name_size + 1);
1267 if (eet_test_close(efn->name == NULL, ef))
1273 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1274 efn->name[name_size] = 0;
1277 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1282 /* The only really usefull peace of code for efn->name (no backward compatibility) */
1283 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1285 /* get hash bucket it should go in */
1286 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1287 efn->next = ef->header->directory->nodes[hash];
1288 ef->header->directory->nodes[hash] = efn;
1290 /* read-only mode, so currently we have no data loaded */
1291 if (ef->mode == EET_FILE_MODE_READ)
1292 efn->data = NULL; /* read-write mode - read everything into ram */
1295 data = malloc(efn->size);
1297 memcpy(data, ef->data + efn->offset, efn->size);
1303 p += HEADER_SIZE + name_size;
1306 } /* eet_internal_read1 */
1308 #endif /* if EET_OLD_EET_FILE_FORMAT */
1311 * this should only be called when the cache lock is already held
1312 * (We could drop this restriction if we add a parameter to eet_test_close
1313 * that indicates if the lock is held or not. For now it is easiest
1314 * to just require that it is always held.)
1317 eet_internal_read(Eet_File *ef)
1319 const int *data = (const int *)ef->data;
1321 if (eet_test_close((ef->data == (void *)-1) || (ef->data == NULL), ef))
1324 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1327 switch (ntohl(*data))
1329 #if EET_OLD_EET_FILE_FORMAT
1330 case EET_MAGIC_FILE:
1331 return eet_internal_read1(ef);
1333 #endif /* if EET_OLD_EET_FILE_FORMAT */
1334 case EET_MAGIC_FILE2:
1335 return eet_internal_read2(ef);
1338 ef->delete_me_now = 1;
1339 eet_internal_close(ef, EINA_TRUE);
1344 } /* eet_internal_read */
1347 eet_internal_close(Eet_File *ef,
1352 /* check to see its' an eet file pointer */
1353 if (eet_check_pointer(ef))
1354 return EET_ERROR_BAD_OBJECT;
1361 /* if its still referenced - dont go any further */
1362 if (ef->references > 0)
1363 goto on_error; /* flush any writes */
1365 err = eet_flush2(ef);
1367 eet_identity_unref(ef->key);
1370 /* if not urgent to delete it - dont free it - leave it in cache */
1371 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1374 /* remove from cache */
1375 if (ef->mode == EET_FILE_MODE_READ)
1376 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1377 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1381 mode == EET_FILE_MODE_READ_WRITE))
1382 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1384 /* we can unlock the cache now */
1393 if (ef->header->directory)
1395 if (ef->header->directory->nodes)
1399 num = (1 << ef->header->directory->size);
1400 for (i = 0; i < num; i++)
1404 while ((efn = ef->header->directory->nodes[i]))
1409 ef->header->directory->nodes[i] = efn->next;
1417 free(ef->header->directory->nodes);
1420 free(ef->header->directory);
1426 eet_dictionary_free(ef->ed);
1432 munmap((void *)ef->data, ef->data_size);
1437 /* zero out ram for struct - caution tactic against stale memory use */
1438 memset(ef, 0, sizeof(Eet_File));
1448 return EET_ERROR_NONE;
1449 } /* eet_internal_close */
1452 eet_memopen_read(const void *data,
1457 if (data == NULL || size == 0)
1460 ef = malloc (sizeof (Eet_File));
1468 ef->magic = EET_MAGIC_FILE;
1470 ef->mode = EET_FILE_MODE_READ;
1473 ef->delete_me_now = 1;
1476 ef->data_size = size;
1478 ef->sha1_length = 0;
1480 /* eet_internal_read expects the cache lock to be held when it is called */
1482 ef = eet_internal_read(ef);
1485 } /* eet_memopen_read */
1488 eet_open(const char *file,
1494 struct stat file_stat;
1499 /* find the current file handle in cache*/
1502 if (mode == EET_FILE_MODE_READ)
1504 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1509 ef->delete_me_now = 1;
1510 eet_internal_close(ef, EINA_TRUE);
1513 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1515 else if ((mode == EET_FILE_MODE_WRITE) ||
1516 (mode == EET_FILE_MODE_READ_WRITE))
1518 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1521 ef->delete_me_now = 1;
1523 eet_internal_close(ef, EINA_TRUE);
1526 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1529 /* try open the file based on mode */
1530 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1532 /* Prevent garbage in futur comparison. */
1533 file_stat.st_mtime = 0;
1535 fp = fopen(file, "rb");
1539 if (fstat(fileno(fp), &file_stat))
1546 if ((mode == EET_FILE_MODE_READ) &&
1547 (file_stat.st_size < ((int)sizeof(int) * 3)))
1555 if (fp == NULL && mode == EET_FILE_MODE_READ)
1560 if (mode != EET_FILE_MODE_WRITE)
1563 memset(&file_stat, 0, sizeof(file_stat));
1570 ((file_stat.st_mtime != ef->mtime) ||
1571 (file_stat.st_size != ef->data_size)))
1573 ef->delete_me_now = 1;
1575 eet_internal_close(ef, EINA_TRUE);
1581 /* reference it up and return it */
1590 file_len = strlen(file) + 1;
1592 /* Allocate struct for eet file and have it zero'd out */
1593 ef = malloc(sizeof(Eet_File) + file_len);
1597 /* fill some of the members */
1601 ef->path = ((char *)ef) + sizeof(Eet_File);
1602 memcpy(ef->path, file, file_len);
1603 ef->magic = EET_MAGIC_FILE;
1607 ef->mtime = file_stat.st_mtime;
1608 ef->writes_pending = 0;
1609 ef->delete_me_now = 0;
1613 ef->sha1_length = 0;
1615 ef->ed = (mode == EET_FILE_MODE_WRITE)
1616 || (ef->readfp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
1617 eet_dictionary_add() : NULL;
1619 if (ef->readfp == NULL &&
1620 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1623 /* if we can't open - bail out */
1624 if (eet_test_close(!ef->readfp, ef))
1627 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1628 /* if we opened for read or read-write */
1629 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1631 ef->data_size = file_stat.st_size;
1632 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1633 MAP_SHARED, fileno(ef->readfp), 0);
1634 if (eet_test_close((ef->data == MAP_FAILED), ef))
1637 ef = eet_internal_read(ef);
1644 if (ef->references == 1)
1646 if (ef->mode == EET_FILE_MODE_READ)
1647 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1649 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1650 (ef->mode == EET_FILE_MODE_READ_WRITE))
1651 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1663 eet_mode_get(Eet_File *ef)
1665 /* check to see its' an eet file pointer */
1666 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1667 return EET_FILE_MODE_INVALID;
1670 } /* eet_mode_get */
1673 eet_identity_x509(Eet_File *ef,
1680 *der_length = ef->x509_length;
1682 return ef->x509_der;
1683 } /* eet_identity_x509 */
1686 eet_identity_signature(Eet_File *ef,
1687 int *signature_length)
1692 if (signature_length)
1693 *signature_length = ef->signature_length;
1695 return ef->signature;
1696 } /* eet_identity_signature */
1699 eet_identity_sha1(Eet_File *ef,
1703 ef->sha1 = eet_identity_compute_sha1(ef->data,
1708 *sha1_length = ef->sha1_length;
1711 } /* eet_identity_sha1 */
1714 eet_identity_set(Eet_File *ef,
1717 Eet_Key *tmp = ef->key;
1720 return EET_ERROR_BAD_OBJECT;
1723 eet_identity_ref(ef->key);
1724 eet_identity_unref(tmp);
1726 /* flags that writes are pending */
1727 ef->writes_pending = 1;
1729 return EET_ERROR_NONE;
1730 } /* eet_identity_set */
1733 eet_close(Eet_File *ef)
1735 return eet_internal_close(ef, EINA_FALSE);
1739 eet_read_cipher(Eet_File *ef,
1742 const char *cipher_key)
1751 /* check to see its' an eet file pointer */
1752 if (eet_check_pointer(ef))
1758 if ((ef->mode != EET_FILE_MODE_READ) &&
1759 (ef->mode != EET_FILE_MODE_READ_WRITE))
1762 /* no header, return NULL */
1763 if (eet_check_header(ef))
1768 /* hunt hash bucket */
1769 efn = find_node_by_name(ef, name);
1773 /* get size (uncompressed, if compressed at all) */
1774 size = efn->data_size;
1777 data = malloc(size);
1781 /* uncompressed data */
1782 if (efn->compression == 0)
1784 void *data_deciphered = NULL;
1785 unsigned int data_deciphered_sz = 0;
1786 /* if we alreayd have the data in ram... copy that */
1789 memcpy(data, efn->data, efn->size);
1791 if (!read_data_from_disk(ef, efn, data, size))
1794 if (efn->ciphered && cipher_key)
1796 if (eet_decipher(data, size, cipher_key, strlen(cipher_key),
1797 &data_deciphered, &data_deciphered_sz))
1799 if (data_deciphered)
1800 free(data_deciphered);
1806 data = data_deciphered;
1807 size = data_deciphered_sz;
1810 /* compressed data */
1814 void *data_deciphered = NULL;
1815 unsigned int data_deciphered_sz = 0;
1817 int compr_size = efn->size;
1820 /* if we already have the data in ram... copy that */
1822 tmp_data = efn->data;
1825 tmp_data = malloc(compr_size);
1831 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1838 if (efn->ciphered && cipher_key)
1840 if (eet_decipher(tmp_data, compr_size, cipher_key,
1841 strlen(cipher_key), &data_deciphered,
1842 &data_deciphered_sz))
1847 if (data_deciphered)
1848 free(data_deciphered);
1854 tmp_data = data_deciphered;
1855 compr_size = data_deciphered_sz;
1860 if (uncompress((Bytef *)data, &dlen,
1861 tmp_data, (uLongf)compr_size))
1875 if (data[size - 1] != '\0')
1878 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1885 /* fill in return values */
1895 } /* eet_read_cipher */
1898 eet_read(Eet_File *ef,
1902 return eet_read_cipher(ef, name, size_ret, NULL);
1906 eet_read_direct(Eet_File *ef,
1911 const char *data = NULL;
1917 /* check to see its' an eet file pointer */
1918 if (eet_check_pointer(ef))
1924 if ((ef->mode != EET_FILE_MODE_READ) &&
1925 (ef->mode != EET_FILE_MODE_READ_WRITE))
1928 /* no header, return NULL */
1929 if (eet_check_header(ef))
1934 /* hunt hash bucket */
1935 efn = find_node_by_name(ef, name);
1939 if (efn->offset < 0 && efn->data == NULL)
1942 /* get size (uncompressed, if compressed at all) */
1943 size = efn->data_size;
1947 data = efn->data ? efn->data : ef->data + efn->offset;
1949 /* handle alias case */
1950 if (efn->compression)
1953 int compr_size = efn->size;
1956 tmp = alloca(sizeof (compr_size));
1959 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1960 (uLongf)compr_size))
1963 if (tmp[compr_size - 1] != '\0')
1968 return eet_read_direct(ef, tmp, size_ret);
1974 if (data[size - 1] != '\0')
1979 return eet_read_direct(ef, data, size_ret);
1982 /* uncompressed data */
1983 if (efn->compression == 0
1984 && efn->ciphered == 0)
1985 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1989 /* fill in return values */
2000 } /* eet_read_direct */
2003 eet_alias(Eet_File *ef,
2005 const char *destination,
2010 Eina_Bool exists_already = EINA_FALSE;
2014 /* check to see its' an eet file pointer */
2015 if (eet_check_pointer(ef))
2018 if ((!name) || (!destination))
2021 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2022 (ef->mode != EET_FILE_MODE_READ_WRITE))
2029 /* allocate header */
2030 ef->header = calloc(1, sizeof(Eet_File_Header));
2034 ef->header->magic = EET_MAGIC_FILE_HEADER;
2035 /* allocate directory block in ram */
2036 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2037 if (!ef->header->directory)
2044 /* 8 bit hash table (256 buckets) */
2045 ef->header->directory->size = 8;
2046 /* allocate base hash table */
2047 ef->header->directory->nodes =
2048 calloc(1, sizeof(Eet_File_Node *) *
2049 (1 << ef->header->directory->size));
2050 if (!ef->header->directory->nodes)
2052 free(ef->header->directory);
2058 /* figure hash bucket */
2059 hash = _eet_hash_gen(name, ef->header->directory->size);
2062 12 + (((strlen(destination) + 1) * 101) / 100)
2063 : strlen(destination) + 1;
2065 data2 = malloc(data_size);
2069 /* if we want to compress */
2074 /* compress the data with max compression */
2075 buflen = (uLongf)data_size;
2076 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2077 (uLong)strlen(destination) + 1,
2078 Z_BEST_COMPRESSION) != Z_OK)
2084 /* record compressed chunk size */
2085 data_size = (int)buflen;
2086 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2089 data_size = strlen(destination) + 1;
2095 data3 = realloc(data2, data_size);
2102 memcpy(data2, destination, data_size);
2104 /* Does this node already exist? */
2105 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2108 if ((efn->name) && (eet_string_match(efn->name, name)))
2113 efn->compression = !!comp;
2114 efn->size = data_size;
2115 efn->data_size = strlen(destination) + 1;
2118 exists_already = EINA_TRUE;
2122 if (!exists_already)
2124 efn = malloc(sizeof(Eet_File_Node));
2131 efn->name = strdup(name);
2132 efn->name_size = strlen(efn->name) + 1;
2135 efn->next = ef->header->directory->nodes[hash];
2136 ef->header->directory->nodes[hash] = efn;
2140 efn->compression = !!comp;
2141 efn->size = data_size;
2142 efn->data_size = strlen(destination) + 1;
2146 /* flags that writes are pending */
2147 ef->writes_pending = 1;
2158 eet_write_cipher(Eet_File *ef,
2163 const char *cipher_key)
2167 int exists_already = 0;
2171 /* check to see its' an eet file pointer */
2172 if (eet_check_pointer(ef))
2175 if ((!name) || (!data) || (size <= 0))
2178 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2179 (ef->mode != EET_FILE_MODE_READ_WRITE))
2186 /* allocate header */
2187 ef->header = calloc(1, sizeof(Eet_File_Header));
2191 ef->header->magic = EET_MAGIC_FILE_HEADER;
2192 /* allocate directory block in ram */
2193 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2194 if (!ef->header->directory)
2201 /* 8 bit hash table (256 buckets) */
2202 ef->header->directory->size = 8;
2203 /* allocate base hash table */
2204 ef->header->directory->nodes =
2205 calloc(1, sizeof(Eet_File_Node *) *
2206 (1 << ef->header->directory->size));
2207 if (!ef->header->directory->nodes)
2209 free(ef->header->directory);
2215 /* figure hash bucket */
2216 hash = _eet_hash_gen(name, ef->header->directory->size);
2218 data_size = comp ? 12 + ((size * 101) / 100) : size;
2220 if (comp || !cipher_key)
2222 data2 = malloc(data_size);
2227 /* if we want to compress */
2232 /* compress the data with max compression */
2233 buflen = (uLongf)data_size;
2234 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2235 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2241 /* record compressed chunk size */
2242 data_size = (int)buflen;
2243 if (data_size < 0 || data_size >= size)
2252 data3 = realloc(data2, data_size);
2260 void *data_ciphered = NULL;
2261 unsigned int data_ciphered_sz = 0;
2264 tmp = data2 ? data2 : data;
2265 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2266 &data_ciphered, &data_ciphered_sz))
2271 data2 = data_ciphered;
2272 data_size = data_ciphered_sz;
2273 size = (data_size > size) ? data_size : size;
2278 free(data_ciphered);
2285 memcpy(data2, data, size);
2287 /* Does this node already exist? */
2288 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2291 if ((efn->name) && (eet_string_match(efn->name, name)))
2295 efn->ciphered = cipher_key ? 1 : 0;
2296 efn->compression = !!comp;
2297 efn->size = data_size;
2298 efn->data_size = size;
2305 if (!exists_already)
2307 efn = malloc(sizeof(Eet_File_Node));
2314 efn->name = strdup(name);
2315 efn->name_size = strlen(efn->name) + 1;
2318 efn->next = ef->header->directory->nodes[hash];
2319 ef->header->directory->nodes[hash] = efn;
2322 efn->ciphered = cipher_key ? 1 : 0;
2323 efn->compression = !!comp;
2324 efn->size = data_size;
2325 efn->data_size = size;
2329 /* flags that writes are pending */
2330 ef->writes_pending = 1;
2337 } /* eet_write_cipher */
2340 eet_write(Eet_File *ef,
2346 return eet_write_cipher(ef, name, data, size, comp, NULL);
2350 eet_delete(Eet_File *ef,
2354 Eet_File_Node *pefn;
2356 int exists_already = 0;
2358 /* check to see its' an eet file pointer */
2359 if (eet_check_pointer(ef))
2365 /* deleting keys is only possible in RW or WRITE mode */
2366 if (ef->mode == EET_FILE_MODE_READ)
2369 if (eet_check_header(ef))
2374 /* figure hash bucket */
2375 hash = _eet_hash_gen(name, ef->header->directory->size);
2377 /* Does this node already exist? */
2378 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2380 pefn = efn, efn = efn->next)
2383 if (eet_string_match(efn->name, name))
2389 ef->header->directory->nodes[hash] = efn->next;
2391 pefn->next = efn->next;
2401 /* flags that writes are pending */
2403 ef->writes_pending = 1;
2407 /* update access time */
2408 return exists_already;
2411 EAPI Eet_Dictionary *
2412 eet_dictionary_get(Eet_File *ef)
2414 if (eet_check_pointer(ef))
2418 } /* eet_dictionary_get */
2421 eet_list(Eet_File *ef,
2426 char **list_ret = NULL;
2428 int list_count_alloc = 0;
2431 /* check to see its' an eet file pointer */
2432 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2434 ((ef->mode != EET_FILE_MODE_READ) &&
2435 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2443 if (!strcmp(glob, "*"))
2448 /* loop through all entries */
2449 num = (1 << ef->header->directory->size);
2450 for (i = 0; i < num; i++)
2452 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2454 /* if the entry matches the input glob
2455 * check for * explicitly, because on some systems, * isn't well
2458 if ((!glob) || !fnmatch(glob, efn->name, 0))
2460 /* add it to our list */
2463 /* only realloc in 32 entry chunks */
2464 if (list_count > list_count_alloc)
2466 char **new_list = NULL;
2468 list_count_alloc += 64;
2470 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2478 list_ret = new_list;
2481 /* put pointer of name string in */
2482 list_ret[list_count - 1] = efn->name;
2489 /* return count and list */
2491 *count_ret = list_count;
2505 eet_num_entries(Eet_File *ef)
2507 int i, num, ret = 0;
2510 /* check to see its' an eet file pointer */
2511 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2512 ((ef->mode != EET_FILE_MODE_READ) &&
2513 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2518 /* loop through all entries */
2519 num = (1 << ef->header->directory->size);
2520 for (i = 0; i < num; i++)
2522 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2529 } /* eet_num_entries */
2531 static Eet_File_Node *
2532 find_node_by_name(Eet_File *ef,
2538 /* get hash bucket this should be in */
2539 hash = _eet_hash_gen(name, ef->header->directory->size);
2541 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2543 if (eet_string_match(efn->name, name))
2548 } /* find_node_by_name */
2551 read_data_from_disk(Eet_File *ef,
2556 if (efn->offset < 0)
2561 if ((efn->offset + len) > ef->data_size)
2564 memcpy(buf, ef->data + efn->offset, len);
2571 /* seek to data location */
2572 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2576 len = fread(buf, len, 1, ef->readfp);
2580 } /* read_data_from_disk */