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))
964 if (efn) free(efn); /* yes i know - we only get here if
965 * efn is null/0 -> trying to shut up
966 * warning tools like cppcheck */
970 /* get entrie header */
971 GET_INT(efn->offset, data, idx);
972 GET_INT(efn->size, data, idx);
973 GET_INT(efn->data_size, data, idx);
974 GET_INT(name_offset, data, idx);
975 GET_INT(name_size, data, idx);
976 GET_INT(flag, data, idx);
978 efn->compression = flag & 0x1 ? 1 : 0;
979 efn->ciphered = flag & 0x2 ? 1 : 0;
980 efn->alias = flag & 0x4 ? 1 : 0;
982 #define EFN_TEST(Test, Ef, Efn)\
983 if (eet_test_close(Test, Ef))\
989 /* check data pointer position */
990 EFN_TEST(!((efn->size > 0)
991 && (efn->offset + efn->size <= ef->data_size)
992 && (efn->offset > bytes_dictionary_entries +
993 bytes_directory_entries)), ef, efn);
995 /* check name position */
996 EFN_TEST(!((name_size > 0)
997 && (name_offset + name_size < ef->data_size)
998 && (name_offset >= bytes_dictionary_entries +
999 bytes_directory_entries)), ef, efn);
1001 name = start + name_offset;
1003 /* check '\0' at the end of name string */
1004 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
1007 efn->name = (char *)name;
1008 efn->name_size = name_size;
1010 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1011 efn->next = ef->header->directory->nodes[hash];
1012 ef->header->directory->nodes[hash] = efn;
1014 /* read-only mode, so currently we have no data loaded */
1015 if (ef->mode == EET_FILE_MODE_READ)
1016 efn->data = NULL; /* read-write mode - read everything into ram */
1019 efn->data = malloc(efn->size);
1021 memcpy(efn->data, ef->data + efn->offset, efn->size);
1024 /* compute the possible position of a signature */
1025 if (signature_base_offset < efn->offset + efn->size)
1026 signature_base_offset = efn->offset + efn->size;
1031 if (num_dictionary_entries)
1033 const int *dico = (const int *)ef->data +
1034 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1035 EET_FILE2_HEADER_COUNT;
1038 if (eet_test_close((num_dictionary_entries *
1039 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1040 (bytes_dictionary_entries + bytes_directory_entries),
1044 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1045 if (eet_test_close(!ef->ed, ef))
1048 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1049 if (eet_test_close(!ef->ed->all, ef))
1052 ef->ed->count = num_dictionary_entries;
1053 ef->ed->total = num_dictionary_entries;
1054 ef->ed->start = start + bytes_dictionary_entries +
1055 bytes_directory_entries;
1056 ef->ed->end = ef->ed->start;
1058 for (j = 0; j < ef->ed->count; ++j)
1063 GET_INT(hash, dico, idx);
1064 GET_INT(offset, dico, idx);
1065 GET_INT(ef->ed->all[j].len, dico, idx);
1066 GET_INT(ef->ed->all[j].prev, dico, idx);
1067 GET_INT(ef->ed->all[j].next, dico, idx);
1069 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1070 So stick to int and check the value. */
1071 if (eet_test_close(hash & 0xFFFFFF00, ef))
1074 /* Check string position */
1075 if (eet_test_close(!((ef->ed->all[j].len > 0)
1077 (bytes_dictionary_entries +
1078 bytes_directory_entries))
1079 && (offset + ef->ed->all[j].len <
1080 ef->data_size)), ef))
1083 ef->ed->all[j].mmap = start + offset;
1084 ef->ed->all[j].str = NULL;
1086 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
1087 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
1089 /* Check '\0' at the end of the string */
1090 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] !=
1094 ef->ed->all[j].hash = hash;
1095 if (ef->ed->all[j].prev == -1)
1096 ef->ed->hash[hash] = j;
1098 /* compute the possible position of a signature */
1099 if (signature_base_offset < offset + ef->ed->all[j].len)
1100 signature_base_offset = offset + ef->ed->all[j].len;
1104 /* Check if the file is signed */
1105 ef->x509_der = NULL;
1106 ef->x509_length = 0;
1107 ef->signature = NULL;
1108 ef->signature_length = 0;
1110 if (signature_base_offset < ef->data_size)
1112 #ifdef HAVE_SIGNATURE
1113 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1114 signature_base_offset;
1115 ef->x509_der = eet_identity_check(ef->data,
1116 signature_base_offset,
1120 ef->data_size - signature_base_offset,
1122 &ef->signature_length,
1125 if (eet_test_close(!ef->x509_der, ef))
1128 #else /* ifdef HAVE_SIGNATURE */
1130 "This file could be signed but you didn't compile the necessary code to check the signature.");
1131 #endif /* ifdef HAVE_SIGNATURE */
1135 } /* eet_internal_read2 */
1137 #if EET_OLD_EET_FILE_FORMAT
1139 eet_internal_read1(Eet_File *ef)
1141 const unsigned char *dyn_buf = NULL;
1142 const unsigned char *p = NULL;
1149 "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.",
1152 /* build header table if read mode */
1155 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1158 #define EXTRACT_INT(Value, Pointer, Index)\
1161 memcpy(&tmp, Pointer + Index, sizeof(int));\
1162 Value = ntohl(tmp);\
1163 Index += sizeof(int);\
1166 /* get entries count and byte count */
1167 EXTRACT_INT(num_entries, ef->data, idx);
1168 EXTRACT_INT(byte_entries, ef->data, idx);
1170 /* we cant have <= 0 values here - invalid */
1171 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1174 /* we can't have more entires than minimum bytes for those! invalid! */
1175 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1178 /* check we will not outrun the file limit */
1179 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1183 /* allocate header */
1184 ef->header = calloc(1, sizeof(Eet_File_Header));
1185 if (eet_test_close(!ef->header, ef))
1188 ef->header->magic = EET_MAGIC_FILE_HEADER;
1190 /* allocate directory block in ram */
1191 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1192 if (eet_test_close(!ef->header->directory, ef))
1195 /* 8 bit hash table (256 buckets) */
1196 ef->header->directory->size = 8;
1197 /* allocate base hash table */
1198 ef->header->directory->nodes =
1199 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1200 if (eet_test_close(!ef->header->directory->nodes, ef))
1203 /* actually read the directory block - all of it, into ram */
1204 dyn_buf = ef->data + idx;
1206 /* parse directory block */
1209 for (i = 0; i < num_entries; i++)
1218 #define HEADER_SIZE (sizeof(int) * 5)
1220 /* out directory block is inconsistent - we have oveerun our */
1221 /* dynamic block buffer before we finished scanning dir entries */
1222 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1225 /* allocate all the ram needed for this stored node accounting */
1226 efn = malloc (sizeof(Eet_File_Node));
1227 if (eet_test_close(!efn, ef))
1229 if (efn) free(efn); /* yes i know - we only get here if
1230 * efn is null/0 -> trying to shut up
1231 * warning tools like cppcheck */
1235 /* get entrie header */
1236 EXTRACT_INT(efn->offset, p, indexn);
1237 EXTRACT_INT(efn->compression, p, indexn);
1238 EXTRACT_INT(efn->size, p, indexn);
1239 EXTRACT_INT(efn->data_size, p, indexn);
1240 EXTRACT_INT(name_size, p, indexn);
1242 efn->name_size = name_size;
1247 if (eet_test_close(efn->size <= 0, ef))
1253 /* invalid name_size */
1254 if (eet_test_close(name_size <= 0, ef))
1260 /* reading name would mean falling off end of dyn_buf - invalid */
1261 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1267 /* This code is useless if we dont want backward compatibility */
1269 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1272 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1276 efn->name = malloc(sizeof(char) * name_size + 1);
1277 if (eet_test_close(!efn->name, ef))
1283 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1284 efn->name[name_size] = 0;
1287 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1292 /* The only really usefull peace of code for efn->name (no backward compatibility) */
1293 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1295 /* get hash bucket it should go in */
1296 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1297 efn->next = ef->header->directory->nodes[hash];
1298 ef->header->directory->nodes[hash] = efn;
1300 /* read-only mode, so currently we have no data loaded */
1301 if (ef->mode == EET_FILE_MODE_READ)
1302 efn->data = NULL; /* read-write mode - read everything into ram */
1305 data = malloc(efn->size);
1307 memcpy(data, ef->data + efn->offset, efn->size);
1313 p += HEADER_SIZE + name_size;
1316 } /* eet_internal_read1 */
1318 #endif /* if EET_OLD_EET_FILE_FORMAT */
1321 * this should only be called when the cache lock is already held
1322 * (We could drop this restriction if we add a parameter to eet_test_close
1323 * that indicates if the lock is held or not. For now it is easiest
1324 * to just require that it is always held.)
1327 eet_internal_read(Eet_File *ef)
1329 const int *data = (const int *)ef->data;
1331 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1334 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1337 switch (ntohl(*data))
1339 #if EET_OLD_EET_FILE_FORMAT
1340 case EET_MAGIC_FILE:
1341 return eet_internal_read1(ef);
1343 #endif /* if EET_OLD_EET_FILE_FORMAT */
1344 case EET_MAGIC_FILE2:
1345 return eet_internal_read2(ef);
1348 ef->delete_me_now = 1;
1349 eet_internal_close(ef, EINA_TRUE);
1354 } /* eet_internal_read */
1357 eet_internal_close(Eet_File *ef,
1362 /* check to see its' an eet file pointer */
1363 if (eet_check_pointer(ef))
1364 return EET_ERROR_BAD_OBJECT;
1371 /* if its still referenced - dont go any further */
1372 if (ef->references > 0)
1373 goto on_error; /* flush any writes */
1375 err = eet_flush2(ef);
1377 eet_identity_unref(ef->key);
1380 /* if not urgent to delete it - dont free it - leave it in cache */
1381 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1384 /* remove from cache */
1385 if (ef->mode == EET_FILE_MODE_READ)
1386 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1387 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1391 mode == EET_FILE_MODE_READ_WRITE))
1392 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1394 /* we can unlock the cache now */
1403 if (ef->header->directory)
1405 if (ef->header->directory->nodes)
1409 num = (1 << ef->header->directory->size);
1410 for (i = 0; i < num; i++)
1414 while ((efn = ef->header->directory->nodes[i]))
1419 ef->header->directory->nodes[i] = efn->next;
1427 free(ef->header->directory->nodes);
1430 free(ef->header->directory);
1436 eet_dictionary_free(ef->ed);
1442 munmap((void *)ef->data, ef->data_size);
1447 /* zero out ram for struct - caution tactic against stale memory use */
1448 memset(ef, 0, sizeof(Eet_File));
1458 return EET_ERROR_NONE;
1459 } /* eet_internal_close */
1462 eet_memopen_read(const void *data,
1467 if (!data || size == 0)
1470 ef = malloc (sizeof (Eet_File));
1478 ef->magic = EET_MAGIC_FILE;
1480 ef->mode = EET_FILE_MODE_READ;
1483 ef->delete_me_now = 1;
1486 ef->data_size = size;
1488 ef->sha1_length = 0;
1490 /* eet_internal_read expects the cache lock to be held when it is called */
1492 ef = eet_internal_read(ef);
1495 } /* eet_memopen_read */
1498 eet_open(const char *file,
1504 struct stat file_stat;
1509 /* find the current file handle in cache*/
1512 if (mode == EET_FILE_MODE_READ)
1514 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1519 ef->delete_me_now = 1;
1520 eet_internal_close(ef, EINA_TRUE);
1523 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1525 else if ((mode == EET_FILE_MODE_WRITE) ||
1526 (mode == EET_FILE_MODE_READ_WRITE))
1528 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1531 ef->delete_me_now = 1;
1533 eet_internal_close(ef, EINA_TRUE);
1536 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1539 /* try open the file based on mode */
1540 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1542 /* Prevent garbage in futur comparison. */
1543 file_stat.st_mtime = 0;
1545 fp = fopen(file, "rb");
1549 if (fstat(fileno(fp), &file_stat))
1556 if ((mode == EET_FILE_MODE_READ) &&
1557 (file_stat.st_size < ((int)sizeof(int) * 3)))
1565 if (!fp && mode == EET_FILE_MODE_READ)
1570 if (mode != EET_FILE_MODE_WRITE)
1573 memset(&file_stat, 0, sizeof(file_stat));
1580 ((file_stat.st_mtime != ef->mtime) ||
1581 (file_stat.st_size != ef->data_size)))
1583 ef->delete_me_now = 1;
1585 eet_internal_close(ef, EINA_TRUE);
1591 /* reference it up and return it */
1600 file_len = strlen(file) + 1;
1602 /* Allocate struct for eet file and have it zero'd out */
1603 ef = malloc(sizeof(Eet_File) + file_len);
1607 /* fill some of the members */
1611 ef->path = ((char *)ef) + sizeof(Eet_File);
1612 memcpy(ef->path, file, file_len);
1613 ef->magic = EET_MAGIC_FILE;
1617 ef->mtime = file_stat.st_mtime;
1618 ef->writes_pending = 0;
1619 ef->delete_me_now = 0;
1623 ef->sha1_length = 0;
1625 ef->ed = (mode == EET_FILE_MODE_WRITE)
1626 || (ef->readfp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
1627 eet_dictionary_add() : NULL;
1629 if (ef->readfp == NULL &&
1630 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1633 /* if we can't open - bail out */
1634 if (eet_test_close(!ef->readfp, ef))
1637 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1638 /* if we opened for read or read-write */
1639 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1641 ef->data_size = file_stat.st_size;
1642 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1643 MAP_SHARED, fileno(ef->readfp), 0);
1644 if (eet_test_close((ef->data == MAP_FAILED), ef))
1647 ef = eet_internal_read(ef);
1654 if (ef->references == 1)
1656 if (ef->mode == EET_FILE_MODE_READ)
1657 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1659 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1660 (ef->mode == EET_FILE_MODE_READ_WRITE))
1661 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1673 eet_mode_get(Eet_File *ef)
1675 /* check to see its' an eet file pointer */
1676 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1677 return EET_FILE_MODE_INVALID;
1680 } /* eet_mode_get */
1683 eet_identity_x509(Eet_File *ef,
1690 *der_length = ef->x509_length;
1692 return ef->x509_der;
1693 } /* eet_identity_x509 */
1696 eet_identity_signature(Eet_File *ef,
1697 int *signature_length)
1702 if (signature_length)
1703 *signature_length = ef->signature_length;
1705 return ef->signature;
1706 } /* eet_identity_signature */
1709 eet_identity_sha1(Eet_File *ef,
1713 ef->sha1 = eet_identity_compute_sha1(ef->data,
1718 *sha1_length = ef->sha1_length;
1721 } /* eet_identity_sha1 */
1724 eet_identity_set(Eet_File *ef,
1727 Eet_Key *tmp = ef->key;
1730 return EET_ERROR_BAD_OBJECT;
1733 eet_identity_ref(ef->key);
1734 eet_identity_unref(tmp);
1736 /* flags that writes are pending */
1737 ef->writes_pending = 1;
1739 return EET_ERROR_NONE;
1740 } /* eet_identity_set */
1743 eet_close(Eet_File *ef)
1745 return eet_internal_close(ef, EINA_FALSE);
1749 eet_read_cipher(Eet_File *ef,
1752 const char *cipher_key)
1761 /* check to see its' an eet file pointer */
1762 if (eet_check_pointer(ef))
1768 if ((ef->mode != EET_FILE_MODE_READ) &&
1769 (ef->mode != EET_FILE_MODE_READ_WRITE))
1772 /* no header, return NULL */
1773 if (eet_check_header(ef))
1778 /* hunt hash bucket */
1779 efn = find_node_by_name(ef, name);
1783 /* get size (uncompressed, if compressed at all) */
1784 size = efn->data_size;
1787 data = malloc(size);
1791 /* uncompressed data */
1792 if (efn->compression == 0)
1794 void *data_deciphered = NULL;
1795 unsigned int data_deciphered_sz = 0;
1796 /* if we alreayd have the data in ram... copy that */
1799 memcpy(data, efn->data, efn->size);
1801 if (!read_data_from_disk(ef, efn, data, size))
1804 if (efn->ciphered && cipher_key)
1806 if (eet_decipher(data, size, cipher_key, strlen(cipher_key),
1807 &data_deciphered, &data_deciphered_sz))
1809 if (data_deciphered)
1810 free(data_deciphered);
1816 data = data_deciphered;
1817 size = data_deciphered_sz;
1820 /* compressed data */
1824 void *data_deciphered = NULL;
1825 unsigned int data_deciphered_sz = 0;
1827 int compr_size = efn->size;
1830 /* if we already have the data in ram... copy that */
1832 tmp_data = efn->data;
1835 tmp_data = malloc(compr_size);
1841 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1848 if (efn->ciphered && cipher_key)
1850 if (eet_decipher(tmp_data, compr_size, cipher_key,
1851 strlen(cipher_key), &data_deciphered,
1852 &data_deciphered_sz))
1857 if (data_deciphered)
1858 free(data_deciphered);
1864 tmp_data = data_deciphered;
1865 compr_size = data_deciphered_sz;
1870 if (uncompress((Bytef *)data, &dlen,
1871 tmp_data, (uLongf)compr_size))
1885 if (data[size - 1] != '\0')
1888 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1895 /* fill in return values */
1905 } /* eet_read_cipher */
1908 eet_read(Eet_File *ef,
1912 return eet_read_cipher(ef, name, size_ret, NULL);
1916 eet_read_direct(Eet_File *ef,
1921 const char *data = NULL;
1927 /* check to see its' an eet file pointer */
1928 if (eet_check_pointer(ef))
1934 if ((ef->mode != EET_FILE_MODE_READ) &&
1935 (ef->mode != EET_FILE_MODE_READ_WRITE))
1938 /* no header, return NULL */
1939 if (eet_check_header(ef))
1944 /* hunt hash bucket */
1945 efn = find_node_by_name(ef, name);
1949 if (efn->offset < 0 && efn->data == NULL)
1952 /* get size (uncompressed, if compressed at all) */
1953 size = efn->data_size;
1957 data = efn->data ? efn->data : ef->data + efn->offset;
1959 /* handle alias case */
1960 if (efn->compression)
1963 int compr_size = efn->size;
1966 tmp = alloca(sizeof (compr_size));
1969 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1970 (uLongf)compr_size))
1973 if (tmp[compr_size - 1] != '\0')
1978 return eet_read_direct(ef, tmp, size_ret);
1984 if (data[size - 1] != '\0')
1989 return eet_read_direct(ef, data, size_ret);
1992 /* uncompressed data */
1993 if (efn->compression == 0
1994 && efn->ciphered == 0)
1995 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1999 /* fill in return values */
2010 } /* eet_read_direct */
2013 eet_alias(Eet_File *ef,
2015 const char *destination,
2020 Eina_Bool exists_already = EINA_FALSE;
2024 /* check to see its' an eet file pointer */
2025 if (eet_check_pointer(ef))
2028 if ((!name) || (!destination))
2031 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2032 (ef->mode != EET_FILE_MODE_READ_WRITE))
2039 /* allocate header */
2040 ef->header = calloc(1, sizeof(Eet_File_Header));
2044 ef->header->magic = EET_MAGIC_FILE_HEADER;
2045 /* allocate directory block in ram */
2046 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2047 if (!ef->header->directory)
2054 /* 8 bit hash table (256 buckets) */
2055 ef->header->directory->size = 8;
2056 /* allocate base hash table */
2057 ef->header->directory->nodes =
2058 calloc(1, sizeof(Eet_File_Node *) *
2059 (1 << ef->header->directory->size));
2060 if (!ef->header->directory->nodes)
2062 free(ef->header->directory);
2068 /* figure hash bucket */
2069 hash = _eet_hash_gen(name, ef->header->directory->size);
2072 12 + (((strlen(destination) + 1) * 101) / 100)
2073 : strlen(destination) + 1;
2075 data2 = malloc(data_size);
2079 /* if we want to compress */
2084 /* compress the data with max compression */
2085 buflen = (uLongf)data_size;
2086 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2087 (uLong)strlen(destination) + 1,
2088 Z_BEST_COMPRESSION) != Z_OK)
2094 /* record compressed chunk size */
2095 data_size = (int)buflen;
2096 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2099 data_size = strlen(destination) + 1;
2105 data3 = realloc(data2, data_size);
2112 memcpy(data2, destination, data_size);
2114 /* Does this node already exist? */
2115 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2118 if ((efn->name) && (eet_string_match(efn->name, name)))
2123 efn->compression = !!comp;
2124 efn->size = data_size;
2125 efn->data_size = strlen(destination) + 1;
2128 exists_already = EINA_TRUE;
2132 if (!exists_already)
2134 efn = malloc(sizeof(Eet_File_Node));
2141 efn->name = strdup(name);
2142 efn->name_size = strlen(efn->name) + 1;
2145 efn->next = ef->header->directory->nodes[hash];
2146 ef->header->directory->nodes[hash] = efn;
2150 efn->compression = !!comp;
2151 efn->size = data_size;
2152 efn->data_size = strlen(destination) + 1;
2156 /* flags that writes are pending */
2157 ef->writes_pending = 1;
2168 eet_write_cipher(Eet_File *ef,
2173 const char *cipher_key)
2177 int exists_already = 0;
2181 /* check to see its' an eet file pointer */
2182 if (eet_check_pointer(ef))
2185 if ((!name) || (!data) || (size <= 0))
2188 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2189 (ef->mode != EET_FILE_MODE_READ_WRITE))
2196 /* allocate header */
2197 ef->header = calloc(1, sizeof(Eet_File_Header));
2201 ef->header->magic = EET_MAGIC_FILE_HEADER;
2202 /* allocate directory block in ram */
2203 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2204 if (!ef->header->directory)
2211 /* 8 bit hash table (256 buckets) */
2212 ef->header->directory->size = 8;
2213 /* allocate base hash table */
2214 ef->header->directory->nodes =
2215 calloc(1, sizeof(Eet_File_Node *) *
2216 (1 << ef->header->directory->size));
2217 if (!ef->header->directory->nodes)
2219 free(ef->header->directory);
2225 /* figure hash bucket */
2226 hash = _eet_hash_gen(name, ef->header->directory->size);
2228 data_size = comp ? 12 + ((size * 101) / 100) : size;
2230 if (comp || !cipher_key)
2232 data2 = malloc(data_size);
2237 /* if we want to compress */
2242 /* compress the data with max compression */
2243 buflen = (uLongf)data_size;
2244 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2245 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2251 /* record compressed chunk size */
2252 data_size = (int)buflen;
2253 if (data_size < 0 || data_size >= size)
2262 data3 = realloc(data2, data_size);
2270 void *data_ciphered = NULL;
2271 unsigned int data_ciphered_sz = 0;
2274 tmp = data2 ? data2 : data;
2275 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2276 &data_ciphered, &data_ciphered_sz))
2281 data2 = data_ciphered;
2282 data_size = data_ciphered_sz;
2283 size = (data_size > size) ? data_size : size;
2288 free(data_ciphered);
2295 memcpy(data2, data, size);
2297 /* Does this node already exist? */
2298 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2301 if ((efn->name) && (eet_string_match(efn->name, name)))
2305 efn->ciphered = cipher_key ? 1 : 0;
2306 efn->compression = !!comp;
2307 efn->size = data_size;
2308 efn->data_size = size;
2315 if (!exists_already)
2317 efn = malloc(sizeof(Eet_File_Node));
2324 efn->name = strdup(name);
2325 efn->name_size = strlen(efn->name) + 1;
2328 efn->next = ef->header->directory->nodes[hash];
2329 ef->header->directory->nodes[hash] = efn;
2332 efn->ciphered = cipher_key ? 1 : 0;
2333 efn->compression = !!comp;
2334 efn->size = data_size;
2335 efn->data_size = size;
2339 /* flags that writes are pending */
2340 ef->writes_pending = 1;
2347 } /* eet_write_cipher */
2350 eet_write(Eet_File *ef,
2356 return eet_write_cipher(ef, name, data, size, comp, NULL);
2360 eet_delete(Eet_File *ef,
2364 Eet_File_Node *pefn;
2366 int exists_already = 0;
2368 /* check to see its' an eet file pointer */
2369 if (eet_check_pointer(ef))
2375 /* deleting keys is only possible in RW or WRITE mode */
2376 if (ef->mode == EET_FILE_MODE_READ)
2379 if (eet_check_header(ef))
2384 /* figure hash bucket */
2385 hash = _eet_hash_gen(name, ef->header->directory->size);
2387 /* Does this node already exist? */
2388 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2390 pefn = efn, efn = efn->next)
2393 if (eet_string_match(efn->name, name))
2399 ef->header->directory->nodes[hash] = efn->next;
2401 pefn->next = efn->next;
2411 /* flags that writes are pending */
2413 ef->writes_pending = 1;
2417 /* update access time */
2418 return exists_already;
2421 EAPI Eet_Dictionary *
2422 eet_dictionary_get(Eet_File *ef)
2424 if (eet_check_pointer(ef))
2428 } /* eet_dictionary_get */
2431 eet_list(Eet_File *ef,
2436 char **list_ret = NULL;
2438 int list_count_alloc = 0;
2441 /* check to see its' an eet file pointer */
2442 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2444 ((ef->mode != EET_FILE_MODE_READ) &&
2445 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2453 if (!strcmp(glob, "*"))
2458 /* loop through all entries */
2459 num = (1 << ef->header->directory->size);
2460 for (i = 0; i < num; i++)
2462 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2464 /* if the entry matches the input glob
2465 * check for * explicitly, because on some systems, * isn't well
2468 if ((!glob) || !fnmatch(glob, efn->name, 0))
2470 /* add it to our list */
2473 /* only realloc in 32 entry chunks */
2474 if (list_count > list_count_alloc)
2476 char **new_list = NULL;
2478 list_count_alloc += 64;
2480 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2488 list_ret = new_list;
2491 /* put pointer of name string in */
2492 list_ret[list_count - 1] = efn->name;
2499 /* return count and list */
2501 *count_ret = list_count;
2515 eet_num_entries(Eet_File *ef)
2517 int i, num, ret = 0;
2520 /* check to see its' an eet file pointer */
2521 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2522 ((ef->mode != EET_FILE_MODE_READ) &&
2523 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2528 /* loop through all entries */
2529 num = (1 << ef->header->directory->size);
2530 for (i = 0; i < num; i++)
2532 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2539 } /* eet_num_entries */
2541 static Eet_File_Node *
2542 find_node_by_name(Eet_File *ef,
2548 /* get hash bucket this should be in */
2549 hash = _eet_hash_gen(name, ef->header->directory->size);
2551 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2553 if (eet_string_match(efn->name, name))
2558 } /* find_node_by_name */
2561 read_data_from_disk(Eet_File *ef,
2566 if (efn->offset < 0)
2571 if ((efn->offset + len) > ef->data_size)
2574 memcpy(buf, ef->data + efn->offset, len);
2581 /* seek to data location */
2582 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2586 len = fread(buf, len, 1, ef->readfp);
2590 } /* read_data_from_disk */