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))
348 if (!cache[i]->delete_me_now)
355 } /* eet_cache_find */
357 /* add to end of cache */
358 /* this should only be called when the cache lock is already held */
360 eet_cache_add(Eet_File *ef,
365 Eet_File **new_cache;
369 new_cache_num = *cache_num;
370 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
372 Eet_File *del_ef = NULL;
376 for (i = 0; i < new_cache_num; i++)
378 if (new_cache[i]->references == 0)
380 del_ef = new_cache[i];
387 del_ef->delete_me_now = 1;
388 eet_internal_close(del_ef, EINA_TRUE);
393 new_cache_num = *cache_num;
394 new_cache_alloc = *cache_alloc;
396 if (new_cache_num > new_cache_alloc)
398 new_cache_alloc += 16;
399 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
402 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
407 new_cache[new_cache_num - 1] = ef;
409 *cache_num = new_cache_num;
410 *cache_alloc = new_cache_alloc;
411 } /* eet_cache_add */
413 /* delete from cache */
414 /* this should only be called when the cache lock is already held */
416 eet_cache_del(Eet_File *ef,
421 Eet_File **new_cache;
422 int new_cache_num, new_cache_alloc;
426 new_cache_num = *cache_num;
427 new_cache_alloc = *cache_alloc;
428 if (new_cache_num <= 0)
431 for (i = 0; i < new_cache_num; i++)
433 if (new_cache[i] == ef)
437 if (i >= new_cache_num)
441 for (j = i; j < new_cache_num; j++)
442 new_cache[j] = new_cache[j + 1];
444 if (new_cache_num <= (new_cache_alloc - 16))
446 new_cache_alloc -= 16;
447 if (new_cache_num > 0)
449 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
452 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
464 *cache_num = new_cache_num;
465 *cache_alloc = new_cache_alloc;
466 } /* eet_cache_del */
468 /* internal string match. null friendly, catches same ptr */
470 eet_string_match(const char *s1,
473 /* both null- no match */
480 return (!strcmp(s1, s2));
481 } /* eet_string_match */
483 /* flush out writes to a v2 eet file */
485 eet_flush2(Eet_File *ef)
489 Eet_Error error = EET_ERROR_NONE;
490 int head[EET_FILE2_HEADER_COUNT];
491 int num_directory_entries = 0;
492 int num_dictionary_entries = 0;
493 int bytes_directory_entries = 0;
494 int bytes_dictionary_entries = 0;
495 int bytes_strings = 0;
497 int strings_offset = 0;
502 if (eet_check_pointer(ef))
503 return EET_ERROR_BAD_OBJECT;
505 if (eet_check_header(ef))
506 return EET_ERROR_EMPTY;
508 if (!ef->writes_pending)
509 return EET_ERROR_NONE;
511 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
512 || (ef->mode == EET_FILE_MODE_WRITE))
516 /* opening for write - delete old copy of file right away */
518 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
519 fp = fdopen(fd, "wb");
521 return EET_ERROR_NOT_WRITABLE;
523 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
526 return EET_ERROR_NOT_WRITABLE;
528 /* calculate string base offset and data base offset */
529 num = (1 << ef->header->directory->size);
530 for (i = 0; i < num; ++i)
532 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
534 num_directory_entries++;
535 bytes_strings += strlen(efn->name) + 1;
540 num_dictionary_entries = ef->ed->count;
542 for (i = 0; i < num_dictionary_entries; ++i)
543 bytes_strings += ef->ed->all[i].len;
546 /* calculate section bytes size */
547 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
548 num_directory_entries + EET_FILE2_HEADER_SIZE;
549 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
550 num_dictionary_entries;
552 /* calculate per entry offset */
553 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
554 data_offset = bytes_directory_entries + bytes_dictionary_entries +
557 for (i = 0; i < num; ++i)
559 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
561 efn->offset = data_offset;
562 data_offset += efn->size;
564 efn->name_offset = strings_offset;
565 strings_offset += efn->name_size;
569 /* calculate dictionary strings offset */
571 ef->ed->offset = strings_offset;
573 /* go thru and write the header */
574 head[0] = (int)htonl((unsigned int)EET_MAGIC_FILE2);
575 head[1] = (int)htonl((unsigned int)num_directory_entries);
576 head[2] = (int)htonl((unsigned int)num_dictionary_entries);
578 fseek(fp, 0, SEEK_SET);
579 if (fwrite(head, sizeof (head), 1, fp) != 1)
582 /* write directories entry */
583 for (i = 0; i < num; i++)
585 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
588 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
590 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
592 ibuf[0] = (int)htonl((unsigned int)efn->offset);
593 ibuf[1] = (int)htonl((unsigned int)efn->size);
594 ibuf[2] = (int)htonl((unsigned int)efn->data_size);
595 ibuf[3] = (int)htonl((unsigned int)efn->name_offset);
596 ibuf[4] = (int)htonl((unsigned int)efn->name_size);
597 ibuf[5] = (int)htonl((unsigned int)flag);
599 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
604 /* write dictionnary */
607 int offset = strings_offset;
609 for (j = 0; j < ef->ed->count; ++j)
611 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
613 sbuf[0] = (int)htonl((unsigned int)ef->ed->all[j].hash);
614 sbuf[1] = (int)htonl((unsigned int)offset);
615 sbuf[2] = (int)htonl((unsigned int)ef->ed->all[j].len);
616 sbuf[3] = (int)htonl((unsigned int)ef->ed->all[j].prev);
617 sbuf[4] = (int)htonl((unsigned int)ef->ed->all[j].next);
619 offset += ef->ed->all[j].len;
621 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
626 /* write directories name */
627 for (i = 0; i < num; i++)
629 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
631 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
639 for (j = 0; j < ef->ed->count; ++j)
641 if (ef->ed->all[j].str)
643 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
648 if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, fp) != 1)
655 for (i = 0; i < num; i++)
657 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
659 if (fwrite(efn->data, efn->size, 1, fp) != 1)
664 /* flush all write to the file. */
666 // this is going to really cause trouble. if ANYTHING this needs to go into a
667 // thread spawned off - but even then...
668 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
669 // manual pages at eachother, but ext4 broke behavior that has been in place
670 // for decades and that 1000's of apps rely on daily - that is that one operation
671 // to disk is committed to disk BEFORE following operations, so the fs retains
672 // a consistent state
673 // fsync(fileno(fp));
675 /* append signature if required */
678 error = eet_identity_sign(fp, ef->key);
679 if (error != EET_ERROR_NONE)
683 /* no more writes pending */
684 ef->writes_pending = 0;
688 return EET_ERROR_NONE;
695 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
697 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
699 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
701 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
703 default: error = EET_ERROR_WRITE_ERROR; break;
715 if (++eet_init_count != 1)
716 return eet_init_count;
720 fprintf(stderr, "Eet: Eina init failed");
721 return --eet_init_count;
724 _eet_log_dom_global = eina_log_domain_register("Eet", EET_DEFAULT_LOG_COLOR);
725 if (_eet_log_dom_global < 0)
727 EINA_LOG_ERR("Eet Can not create a general log domain.");
731 if (!eet_node_init())
733 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
734 goto unregister_log_domain;
738 /* Before the library can be used, it must initialize itself if needed. */
739 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
741 gcry_check_version(NULL);
742 /* Disable warning messages about problems with the secure memory subsystem.
743 This command should be run right after gcry_check_version. */
744 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
745 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
746 enabling the use of secure memory. It also drops all extra privileges the
747 process has (i.e. if it is run as setuid (root)). If the argument nbytes
748 is 0, secure memory will be disabled. The minimum amount of secure memory
749 allocated is currently 16384 bytes; you may thus use a value of 1 to
750 request that default size. */
752 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
754 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
757 #ifdef EFL_HAVE_POSIX_THREADS
758 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
760 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
762 #endif /* ifdef EFL_HAVE_POSIX_THREADS */
763 if (gnutls_global_init())
766 #endif /* ifdef HAVE_GNUTLS */
768 ERR_load_crypto_strings();
769 OpenSSL_add_all_algorithms();
770 #endif /* ifdef HAVE_OPENSSL */
772 return eet_init_count;
776 unregister_log_domain:
777 eina_log_domain_unregister(_eet_log_dom_global);
778 _eet_log_dom_global = -1;
781 return --eet_init_count;
787 if (--eet_init_count != 0)
788 return eet_init_count;
793 gnutls_global_deinit();
794 #endif /* ifdef HAVE_GNUTLS */
798 #endif /* ifdef HAVE_OPENSSL */
799 eina_log_domain_unregister(_eet_log_dom_global);
800 _eet_log_dom_global = -1;
803 return eet_init_count;
807 eet_sync(Eet_File *ef)
811 if (eet_check_pointer(ef))
812 return EET_ERROR_BAD_OBJECT;
814 if ((ef->mode != EET_FILE_MODE_WRITE) &&
815 (ef->mode != EET_FILE_MODE_READ_WRITE))
816 return EET_ERROR_NOT_WRITABLE;
818 if (!ef->writes_pending)
819 return EET_ERROR_NONE;
823 ret = eet_flush2(ef);
836 * We need to compute the list of eet file to close separately from the cache,
837 * due to eet_close removing them from the cache after each call.
840 for (i = 0; i < eet_writers_num; i++)
842 if (eet_writers[i]->references <= 0)
846 for (i = 0; i < eet_readers_num; i++)
848 if (eet_readers[i]->references <= 0)
854 Eet_File **closelist = NULL;
856 closelist = alloca(num * sizeof(Eet_File *));
858 for (i = 0; i < eet_writers_num; i++)
860 if (eet_writers[i]->references <= 0)
862 closelist[num] = eet_writers[i];
863 eet_writers[i]->delete_me_now = 1;
868 for (i = 0; i < eet_readers_num; i++)
870 if (eet_readers[i]->references <= 0)
872 closelist[num] = eet_readers[i];
873 eet_readers[i]->delete_me_now = 1;
878 for (i = 0; i < num; i++)
880 eet_internal_close(closelist[i], EINA_TRUE);
885 } /* eet_clearcache */
887 /* FIXME: MMAP race condition in READ_WRITE_MODE */
889 eet_internal_read2(Eet_File *ef)
891 const int *data = (const int *)ef->data;
892 const char *start = (const char *)ef->data;
894 int num_directory_entries;
895 int bytes_directory_entries;
896 int num_dictionary_entries;
897 int bytes_dictionary_entries;
898 int signature_base_offset;
902 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
907 #define GET_INT(Value, Pointer, Index)\
909 Value = ntohl(*Pointer);\
911 Index += sizeof(int);\
914 /* get entries count and byte count */
915 GET_INT(num_directory_entries, data, idx);
916 /* get dictionary count and byte count */
917 GET_INT(num_dictionary_entries, data, idx);
919 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
920 num_directory_entries + EET_FILE2_HEADER_SIZE;
921 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
922 num_dictionary_entries;
924 /* we cant have <= 0 values here - invalid */
925 if (eet_test_close((num_directory_entries <= 0), ef))
928 /* we cant have more bytes directory and bytes in dictionaries than the size of the file */
929 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
933 /* allocate header */
934 ef->header = calloc(1, sizeof(Eet_File_Header));
935 if (eet_test_close(!ef->header, ef))
938 ef->header->magic = EET_MAGIC_FILE_HEADER;
940 /* allocate directory block in ram */
941 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
942 if (eet_test_close(!ef->header->directory, ef))
945 /* 8 bit hash table (256 buckets) */
946 ef->header->directory->size = 8;
947 /* allocate base hash table */
948 ef->header->directory->nodes =
949 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
950 if (eet_test_close(!ef->header->directory->nodes, ef))
953 signature_base_offset = 0;
955 /* actually read the directory block - all of it, into ram */
956 for (i = 0; i < num_directory_entries; ++i)
965 /* out directory block is inconsistent - we have oveerun our */
966 /* dynamic block buffer before we finished scanning dir entries */
967 efn = malloc(sizeof(Eet_File_Node));
968 if (eet_test_close(!efn, ef))
970 if (efn) free(efn); /* yes i know - we only get here if
971 * efn is null/0 -> trying to shut up
972 * warning tools like cppcheck */
976 /* get entrie header */
977 GET_INT(efn->offset, data, idx);
978 GET_INT(efn->size, data, idx);
979 GET_INT(efn->data_size, data, idx);
980 GET_INT(name_offset, data, idx);
981 GET_INT(name_size, data, idx);
982 GET_INT(flag, data, idx);
984 efn->compression = flag & 0x1 ? 1 : 0;
985 efn->ciphered = flag & 0x2 ? 1 : 0;
986 efn->alias = flag & 0x4 ? 1 : 0;
988 #define EFN_TEST(Test, Ef, Efn)\
989 if (eet_test_close(Test, Ef))\
995 /* check data pointer position */
996 EFN_TEST(!((efn->size > 0)
997 && (efn->offset + efn->size <= ef->data_size)
998 && (efn->offset > bytes_dictionary_entries +
999 bytes_directory_entries)), ef, efn);
1001 /* check name position */
1002 EFN_TEST(!((name_size > 0)
1003 && (name_offset + name_size < ef->data_size)
1004 && (name_offset >= bytes_dictionary_entries +
1005 bytes_directory_entries)), ef, efn);
1007 name = start + name_offset;
1009 /* check '\0' at the end of name string */
1010 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
1013 efn->name = (char *)name;
1014 efn->name_size = name_size;
1016 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1017 efn->next = ef->header->directory->nodes[hash];
1018 ef->header->directory->nodes[hash] = efn;
1020 /* read-only mode, so currently we have no data loaded */
1021 if (ef->mode == EET_FILE_MODE_READ)
1022 efn->data = NULL; /* read-write mode - read everything into ram */
1025 efn->data = malloc(efn->size);
1027 memcpy(efn->data, ef->data + efn->offset, efn->size);
1030 /* compute the possible position of a signature */
1031 if (signature_base_offset < efn->offset + efn->size)
1032 signature_base_offset = efn->offset + efn->size;
1037 if (num_dictionary_entries)
1039 const int *dico = (const int *)ef->data +
1040 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1041 EET_FILE2_HEADER_COUNT;
1044 if (eet_test_close((num_dictionary_entries *
1045 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1046 (bytes_dictionary_entries + bytes_directory_entries),
1050 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1051 if (eet_test_close(!ef->ed, ef))
1054 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1055 if (eet_test_close(!ef->ed->all, ef))
1058 ef->ed->count = num_dictionary_entries;
1059 ef->ed->total = num_dictionary_entries;
1060 ef->ed->start = start + bytes_dictionary_entries +
1061 bytes_directory_entries;
1062 ef->ed->end = ef->ed->start;
1064 for (j = 0; j < ef->ed->count; ++j)
1069 GET_INT(hash, dico, idx);
1070 GET_INT(offset, dico, idx);
1071 GET_INT(ef->ed->all[j].len, dico, idx);
1072 GET_INT(ef->ed->all[j].prev, dico, idx);
1073 GET_INT(ef->ed->all[j].next, dico, idx);
1075 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1076 So stick to int and check the value. */
1077 if (eet_test_close(hash & 0xFFFFFF00, ef))
1080 /* Check string position */
1081 if (eet_test_close(!((ef->ed->all[j].len > 0)
1083 (bytes_dictionary_entries +
1084 bytes_directory_entries))
1085 && (offset + ef->ed->all[j].len <
1086 ef->data_size)), ef))
1089 ef->ed->all[j].mmap = start + offset;
1090 ef->ed->all[j].str = NULL;
1092 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
1093 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
1095 /* Check '\0' at the end of the string */
1096 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] !=
1100 ef->ed->all[j].hash = hash;
1101 if (ef->ed->all[j].prev == -1)
1102 ef->ed->hash[hash] = j;
1104 /* compute the possible position of a signature */
1105 if (signature_base_offset < offset + ef->ed->all[j].len)
1106 signature_base_offset = offset + ef->ed->all[j].len;
1110 /* Check if the file is signed */
1111 ef->x509_der = NULL;
1112 ef->x509_length = 0;
1113 ef->signature = NULL;
1114 ef->signature_length = 0;
1116 if (signature_base_offset < ef->data_size)
1118 #ifdef HAVE_SIGNATURE
1119 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1120 signature_base_offset;
1121 ef->x509_der = eet_identity_check(ef->data,
1122 signature_base_offset,
1126 ef->data_size - signature_base_offset,
1128 &ef->signature_length,
1131 if (eet_test_close(!ef->x509_der, ef))
1134 #else /* ifdef HAVE_SIGNATURE */
1136 "This file could be signed but you didn't compile the necessary code to check the signature.");
1137 #endif /* ifdef HAVE_SIGNATURE */
1141 } /* eet_internal_read2 */
1143 #if EET_OLD_EET_FILE_FORMAT
1145 eet_internal_read1(Eet_File *ef)
1147 const unsigned char *dyn_buf = NULL;
1148 const unsigned char *p = NULL;
1155 "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.",
1158 /* build header table if read mode */
1161 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1164 #define EXTRACT_INT(Value, Pointer, Index)\
1167 memcpy(&tmp, Pointer + Index, sizeof(int));\
1168 Value = ntohl(tmp);\
1169 Index += sizeof(int);\
1172 /* get entries count and byte count */
1173 EXTRACT_INT(num_entries, ef->data, idx);
1174 EXTRACT_INT(byte_entries, ef->data, idx);
1176 /* we cant have <= 0 values here - invalid */
1177 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1180 /* we can't have more entires than minimum bytes for those! invalid! */
1181 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1184 /* check we will not outrun the file limit */
1185 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1189 /* allocate header */
1190 ef->header = calloc(1, sizeof(Eet_File_Header));
1191 if (eet_test_close(!ef->header, ef))
1194 ef->header->magic = EET_MAGIC_FILE_HEADER;
1196 /* allocate directory block in ram */
1197 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1198 if (eet_test_close(!ef->header->directory, ef))
1201 /* 8 bit hash table (256 buckets) */
1202 ef->header->directory->size = 8;
1203 /* allocate base hash table */
1204 ef->header->directory->nodes =
1205 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1206 if (eet_test_close(!ef->header->directory->nodes, ef))
1209 /* actually read the directory block - all of it, into ram */
1210 dyn_buf = ef->data + idx;
1212 /* parse directory block */
1215 for (i = 0; i < num_entries; i++)
1224 #define HEADER_SIZE (sizeof(int) * 5)
1226 /* out directory block is inconsistent - we have oveerun our */
1227 /* dynamic block buffer before we finished scanning dir entries */
1228 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1231 /* allocate all the ram needed for this stored node accounting */
1232 efn = malloc (sizeof(Eet_File_Node));
1233 if (eet_test_close(!efn, ef))
1235 if (efn) free(efn); /* yes i know - we only get here if
1236 * efn is null/0 -> trying to shut up
1237 * warning tools like cppcheck */
1241 /* get entrie header */
1242 EXTRACT_INT(efn->offset, p, indexn);
1243 EXTRACT_INT(efn->compression, p, indexn);
1244 EXTRACT_INT(efn->size, p, indexn);
1245 EXTRACT_INT(efn->data_size, p, indexn);
1246 EXTRACT_INT(name_size, p, indexn);
1248 efn->name_size = name_size;
1253 if (eet_test_close(efn->size <= 0, ef))
1259 /* invalid name_size */
1260 if (eet_test_close(name_size <= 0, ef))
1266 /* reading name would mean falling off end of dyn_buf - invalid */
1267 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1273 /* This code is useless if we dont want backward compatibility */
1275 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1278 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1282 efn->name = malloc(sizeof(char) * name_size + 1);
1283 if (eet_test_close(!efn->name, ef))
1289 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1290 efn->name[name_size] = 0;
1293 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1298 /* The only really usefull peace of code for efn->name (no backward compatibility) */
1299 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1301 /* get hash bucket it should go in */
1302 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1303 efn->next = ef->header->directory->nodes[hash];
1304 ef->header->directory->nodes[hash] = efn;
1306 /* read-only mode, so currently we have no data loaded */
1307 if (ef->mode == EET_FILE_MODE_READ)
1308 efn->data = NULL; /* read-write mode - read everything into ram */
1311 data = malloc(efn->size);
1313 memcpy(data, ef->data + efn->offset, efn->size);
1319 p += HEADER_SIZE + name_size;
1322 } /* eet_internal_read1 */
1324 #endif /* if EET_OLD_EET_FILE_FORMAT */
1327 * this should only be called when the cache lock is already held
1328 * (We could drop this restriction if we add a parameter to eet_test_close
1329 * that indicates if the lock is held or not. For now it is easiest
1330 * to just require that it is always held.)
1333 eet_internal_read(Eet_File *ef)
1335 const int *data = (const int *)ef->data;
1337 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1340 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1343 switch (ntohl(*data))
1345 #if EET_OLD_EET_FILE_FORMAT
1346 case EET_MAGIC_FILE:
1347 return eet_internal_read1(ef);
1349 #endif /* if EET_OLD_EET_FILE_FORMAT */
1350 case EET_MAGIC_FILE2:
1351 return eet_internal_read2(ef);
1354 ef->delete_me_now = 1;
1355 eet_internal_close(ef, EINA_TRUE);
1360 } /* eet_internal_read */
1363 eet_internal_close(Eet_File *ef,
1368 /* check to see its' an eet file pointer */
1369 if (eet_check_pointer(ef))
1370 return EET_ERROR_BAD_OBJECT;
1377 /* if its still referenced - dont go any further */
1378 if (ef->references > 0)
1379 goto on_error; /* flush any writes */
1381 err = eet_flush2(ef);
1383 eet_identity_unref(ef->key);
1386 /* if not urgent to delete it - dont free it - leave it in cache */
1387 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1390 /* remove from cache */
1391 if (ef->mode == EET_FILE_MODE_READ)
1392 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1393 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1397 mode == EET_FILE_MODE_READ_WRITE))
1398 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1400 /* we can unlock the cache now */
1409 if (ef->header->directory)
1411 if (ef->header->directory->nodes)
1415 num = (1 << ef->header->directory->size);
1416 for (i = 0; i < num; i++)
1420 while ((efn = ef->header->directory->nodes[i]))
1425 ef->header->directory->nodes[i] = efn->next;
1433 free(ef->header->directory->nodes);
1436 free(ef->header->directory);
1442 eet_dictionary_free(ef->ed);
1448 munmap((void *)ef->data, ef->data_size);
1453 /* zero out ram for struct - caution tactic against stale memory use */
1454 memset(ef, 0, sizeof(Eet_File));
1464 return EET_ERROR_NONE;
1465 } /* eet_internal_close */
1468 eet_memopen_read(const void *data,
1473 if (!data || size == 0)
1476 ef = malloc (sizeof (Eet_File));
1484 ef->magic = EET_MAGIC_FILE;
1486 ef->mode = EET_FILE_MODE_READ;
1489 ef->delete_me_now = 1;
1492 ef->data_size = size;
1494 ef->sha1_length = 0;
1496 /* eet_internal_read expects the cache lock to be held when it is called */
1498 ef = eet_internal_read(ef);
1501 } /* eet_memopen_read */
1504 eet_open(const char *file,
1510 struct stat file_stat;
1515 /* find the current file handle in cache*/
1518 if (mode == EET_FILE_MODE_READ)
1520 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1525 ef->delete_me_now = 1;
1526 eet_internal_close(ef, EINA_TRUE);
1529 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1531 else if ((mode == EET_FILE_MODE_WRITE) ||
1532 (mode == EET_FILE_MODE_READ_WRITE))
1534 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1537 ef->delete_me_now = 1;
1539 eet_internal_close(ef, EINA_TRUE);
1542 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1545 /* try open the file based on mode */
1546 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1548 /* Prevent garbage in futur comparison. */
1549 file_stat.st_mtime = 0;
1551 fp = fopen(file, "rb");
1555 if (fstat(fileno(fp), &file_stat))
1562 if ((mode == EET_FILE_MODE_READ) &&
1563 (file_stat.st_size < ((int)sizeof(int) * 3)))
1571 if (!fp && mode == EET_FILE_MODE_READ)
1576 if (mode != EET_FILE_MODE_WRITE)
1579 memset(&file_stat, 0, sizeof(file_stat));
1586 ((file_stat.st_mtime != ef->mtime) ||
1587 (file_stat.st_size != ef->data_size)))
1589 ef->delete_me_now = 1;
1591 eet_internal_close(ef, EINA_TRUE);
1597 /* reference it up and return it */
1606 file_len = strlen(file) + 1;
1608 /* Allocate struct for eet file and have it zero'd out */
1609 ef = malloc(sizeof(Eet_File) + file_len);
1613 /* fill some of the members */
1617 ef->path = ((char *)ef) + sizeof(Eet_File);
1618 memcpy(ef->path, file, file_len);
1619 ef->magic = EET_MAGIC_FILE;
1623 ef->mtime = file_stat.st_mtime;
1624 ef->writes_pending = 0;
1625 ef->delete_me_now = 0;
1629 ef->sha1_length = 0;
1631 ef->ed = (mode == EET_FILE_MODE_WRITE)
1632 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1633 eet_dictionary_add() : NULL;
1636 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1639 /* if we can't open - bail out */
1640 if (eet_test_close(!ef->readfp, ef))
1643 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1644 /* if we opened for read or read-write */
1645 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1647 ef->data_size = file_stat.st_size;
1648 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1649 MAP_SHARED, fileno(ef->readfp), 0);
1650 if (eet_test_close((ef->data == MAP_FAILED), ef))
1653 ef = eet_internal_read(ef);
1660 if (ef->references == 1)
1662 if (ef->mode == EET_FILE_MODE_READ)
1663 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1665 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1666 (ef->mode == EET_FILE_MODE_READ_WRITE))
1667 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1679 eet_mode_get(Eet_File *ef)
1681 /* check to see its' an eet file pointer */
1682 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1683 return EET_FILE_MODE_INVALID;
1686 } /* eet_mode_get */
1689 eet_identity_x509(Eet_File *ef,
1696 *der_length = ef->x509_length;
1698 return ef->x509_der;
1699 } /* eet_identity_x509 */
1702 eet_identity_signature(Eet_File *ef,
1703 int *signature_length)
1708 if (signature_length)
1709 *signature_length = ef->signature_length;
1711 return ef->signature;
1712 } /* eet_identity_signature */
1715 eet_identity_sha1(Eet_File *ef,
1719 ef->sha1 = eet_identity_compute_sha1(ef->data,
1724 *sha1_length = ef->sha1_length;
1727 } /* eet_identity_sha1 */
1730 eet_identity_set(Eet_File *ef,
1733 Eet_Key *tmp = ef->key;
1736 return EET_ERROR_BAD_OBJECT;
1739 eet_identity_ref(ef->key);
1740 eet_identity_unref(tmp);
1742 /* flags that writes are pending */
1743 ef->writes_pending = 1;
1745 return EET_ERROR_NONE;
1746 } /* eet_identity_set */
1749 eet_close(Eet_File *ef)
1751 return eet_internal_close(ef, EINA_FALSE);
1755 eet_read_cipher(Eet_File *ef,
1758 const char *cipher_key)
1767 /* check to see its' an eet file pointer */
1768 if (eet_check_pointer(ef))
1774 if ((ef->mode != EET_FILE_MODE_READ) &&
1775 (ef->mode != EET_FILE_MODE_READ_WRITE))
1778 /* no header, return NULL */
1779 if (eet_check_header(ef))
1784 /* hunt hash bucket */
1785 efn = find_node_by_name(ef, name);
1789 /* get size (uncompressed, if compressed at all) */
1790 size = efn->data_size;
1793 data = malloc(size);
1797 /* uncompressed data */
1798 if (efn->compression == 0)
1800 void *data_deciphered = NULL;
1801 unsigned int data_deciphered_sz = 0;
1802 /* if we alreayd have the data in ram... copy that */
1805 memcpy(data, efn->data, efn->size);
1807 if (!read_data_from_disk(ef, efn, data, size))
1810 if (efn->ciphered && cipher_key)
1812 if (eet_decipher(data, size, cipher_key, strlen(cipher_key),
1813 &data_deciphered, &data_deciphered_sz))
1815 if (data_deciphered)
1816 free(data_deciphered);
1822 data = data_deciphered;
1823 size = data_deciphered_sz;
1826 /* compressed data */
1830 void *data_deciphered = NULL;
1831 unsigned int data_deciphered_sz = 0;
1833 int compr_size = efn->size;
1836 /* if we already have the data in ram... copy that */
1838 tmp_data = efn->data;
1841 tmp_data = malloc(compr_size);
1847 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1854 if (efn->ciphered && cipher_key)
1856 if (eet_decipher(tmp_data, compr_size, cipher_key,
1857 strlen(cipher_key), &data_deciphered,
1858 &data_deciphered_sz))
1863 if (data_deciphered)
1864 free(data_deciphered);
1870 tmp_data = data_deciphered;
1871 compr_size = data_deciphered_sz;
1876 if (uncompress((Bytef *)data, &dlen,
1877 tmp_data, (uLongf)compr_size))
1891 if (data[size - 1] != '\0')
1894 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1901 /* fill in return values */
1911 } /* eet_read_cipher */
1914 eet_read(Eet_File *ef,
1918 return eet_read_cipher(ef, name, size_ret, NULL);
1922 eet_read_direct(Eet_File *ef,
1927 const char *data = NULL;
1933 /* check to see its' an eet file pointer */
1934 if (eet_check_pointer(ef))
1940 if ((ef->mode != EET_FILE_MODE_READ) &&
1941 (ef->mode != EET_FILE_MODE_READ_WRITE))
1944 /* no header, return NULL */
1945 if (eet_check_header(ef))
1950 /* hunt hash bucket */
1951 efn = find_node_by_name(ef, name);
1955 if (efn->offset < 0 && !efn->data)
1958 /* get size (uncompressed, if compressed at all) */
1959 size = efn->data_size;
1963 data = efn->data ? efn->data : ef->data + efn->offset;
1965 /* handle alias case */
1966 if (efn->compression)
1969 int compr_size = efn->size;
1972 tmp = alloca(sizeof (compr_size));
1975 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1976 (uLongf)compr_size))
1979 if (tmp[compr_size - 1] != '\0')
1984 return eet_read_direct(ef, tmp, size_ret);
1990 if (data[size - 1] != '\0')
1995 return eet_read_direct(ef, data, size_ret);
1998 /* uncompressed data */
1999 if (efn->compression == 0
2000 && efn->ciphered == 0)
2001 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
2005 /* fill in return values */
2016 } /* eet_read_direct */
2019 eet_alias(Eet_File *ef,
2021 const char *destination,
2026 Eina_Bool exists_already = EINA_FALSE;
2030 /* check to see its' an eet file pointer */
2031 if (eet_check_pointer(ef))
2034 if ((!name) || (!destination))
2037 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2038 (ef->mode != EET_FILE_MODE_READ_WRITE))
2045 /* allocate header */
2046 ef->header = calloc(1, sizeof(Eet_File_Header));
2050 ef->header->magic = EET_MAGIC_FILE_HEADER;
2051 /* allocate directory block in ram */
2052 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2053 if (!ef->header->directory)
2060 /* 8 bit hash table (256 buckets) */
2061 ef->header->directory->size = 8;
2062 /* allocate base hash table */
2063 ef->header->directory->nodes =
2064 calloc(1, sizeof(Eet_File_Node *) *
2065 (1 << ef->header->directory->size));
2066 if (!ef->header->directory->nodes)
2068 free(ef->header->directory);
2074 /* figure hash bucket */
2075 hash = _eet_hash_gen(name, ef->header->directory->size);
2078 12 + (((strlen(destination) + 1) * 101) / 100)
2079 : strlen(destination) + 1;
2081 data2 = malloc(data_size);
2085 /* if we want to compress */
2090 /* compress the data with max compression */
2091 buflen = (uLongf)data_size;
2092 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2093 (uLong)strlen(destination) + 1,
2094 Z_BEST_COMPRESSION) != Z_OK)
2100 /* record compressed chunk size */
2101 data_size = (int)buflen;
2102 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2105 data_size = strlen(destination) + 1;
2111 data3 = realloc(data2, data_size);
2118 memcpy(data2, destination, data_size);
2120 /* Does this node already exist? */
2121 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2124 if ((efn->name) && (eet_string_match(efn->name, name)))
2129 efn->compression = !!comp;
2130 efn->size = data_size;
2131 efn->data_size = strlen(destination) + 1;
2134 exists_already = EINA_TRUE;
2138 if (!exists_already)
2140 efn = malloc(sizeof(Eet_File_Node));
2147 efn->name = strdup(name);
2148 efn->name_size = strlen(efn->name) + 1;
2151 efn->next = ef->header->directory->nodes[hash];
2152 ef->header->directory->nodes[hash] = efn;
2156 efn->compression = !!comp;
2157 efn->size = data_size;
2158 efn->data_size = strlen(destination) + 1;
2162 /* flags that writes are pending */
2163 ef->writes_pending = 1;
2174 eet_write_cipher(Eet_File *ef,
2179 const char *cipher_key)
2183 int exists_already = 0;
2187 /* check to see its' an eet file pointer */
2188 if (eet_check_pointer(ef))
2191 if ((!name) || (!data) || (size <= 0))
2194 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2195 (ef->mode != EET_FILE_MODE_READ_WRITE))
2202 /* allocate header */
2203 ef->header = calloc(1, sizeof(Eet_File_Header));
2207 ef->header->magic = EET_MAGIC_FILE_HEADER;
2208 /* allocate directory block in ram */
2209 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2210 if (!ef->header->directory)
2217 /* 8 bit hash table (256 buckets) */
2218 ef->header->directory->size = 8;
2219 /* allocate base hash table */
2220 ef->header->directory->nodes =
2221 calloc(1, sizeof(Eet_File_Node *) *
2222 (1 << ef->header->directory->size));
2223 if (!ef->header->directory->nodes)
2225 free(ef->header->directory);
2231 /* figure hash bucket */
2232 hash = _eet_hash_gen(name, ef->header->directory->size);
2234 data_size = comp ? 12 + ((size * 101) / 100) : size;
2236 if (comp || !cipher_key)
2238 data2 = malloc(data_size);
2243 /* if we want to compress */
2248 /* compress the data with max compression */
2249 buflen = (uLongf)data_size;
2250 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2251 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2257 /* record compressed chunk size */
2258 data_size = (int)buflen;
2259 if (data_size < 0 || data_size >= size)
2268 data3 = realloc(data2, data_size);
2276 void *data_ciphered = NULL;
2277 unsigned int data_ciphered_sz = 0;
2280 tmp = comp ? data2 : data;
2281 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2282 &data_ciphered, &data_ciphered_sz))
2287 data2 = data_ciphered;
2288 data_size = data_ciphered_sz;
2289 size = (data_size > size) ? data_size : size;
2294 free(data_ciphered);
2301 memcpy(data2, data, size);
2303 /* Does this node already exist? */
2304 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2307 if ((efn->name) && (eet_string_match(efn->name, name)))
2311 efn->ciphered = cipher_key ? 1 : 0;
2312 efn->compression = !!comp;
2313 efn->size = data_size;
2314 efn->data_size = size;
2321 if (!exists_already)
2323 efn = malloc(sizeof(Eet_File_Node));
2330 efn->name = strdup(name);
2331 efn->name_size = strlen(efn->name) + 1;
2334 efn->next = ef->header->directory->nodes[hash];
2335 ef->header->directory->nodes[hash] = efn;
2338 efn->ciphered = cipher_key ? 1 : 0;
2339 efn->compression = !!comp;
2340 efn->size = data_size;
2341 efn->data_size = size;
2345 /* flags that writes are pending */
2346 ef->writes_pending = 1;
2353 } /* eet_write_cipher */
2356 eet_write(Eet_File *ef,
2362 return eet_write_cipher(ef, name, data, size, comp, NULL);
2366 eet_delete(Eet_File *ef,
2370 Eet_File_Node *pefn;
2372 int exists_already = 0;
2374 /* check to see its' an eet file pointer */
2375 if (eet_check_pointer(ef))
2381 /* deleting keys is only possible in RW or WRITE mode */
2382 if (ef->mode == EET_FILE_MODE_READ)
2385 if (eet_check_header(ef))
2390 /* figure hash bucket */
2391 hash = _eet_hash_gen(name, ef->header->directory->size);
2393 /* Does this node already exist? */
2394 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2396 pefn = efn, efn = efn->next)
2399 if (eet_string_match(efn->name, name))
2405 ef->header->directory->nodes[hash] = efn->next;
2407 pefn->next = efn->next;
2417 /* flags that writes are pending */
2419 ef->writes_pending = 1;
2423 /* update access time */
2424 return exists_already;
2427 EAPI Eet_Dictionary *
2428 eet_dictionary_get(Eet_File *ef)
2430 if (eet_check_pointer(ef))
2434 } /* eet_dictionary_get */
2437 eet_list(Eet_File *ef,
2442 char **list_ret = NULL;
2444 int list_count_alloc = 0;
2447 /* check to see its' an eet file pointer */
2448 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2450 ((ef->mode != EET_FILE_MODE_READ) &&
2451 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2459 if (!strcmp(glob, "*"))
2464 /* loop through all entries */
2465 num = (1 << ef->header->directory->size);
2466 for (i = 0; i < num; i++)
2468 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2470 /* if the entry matches the input glob
2471 * check for * explicitly, because on some systems, * isn't well
2474 if ((!glob) || !fnmatch(glob, efn->name, 0))
2476 /* add it to our list */
2479 /* only realloc in 32 entry chunks */
2480 if (list_count > list_count_alloc)
2482 char **new_list = NULL;
2484 list_count_alloc += 64;
2486 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2494 list_ret = new_list;
2497 /* put pointer of name string in */
2498 list_ret[list_count - 1] = efn->name;
2505 /* return count and list */
2507 *count_ret = list_count;
2521 eet_num_entries(Eet_File *ef)
2523 int i, num, ret = 0;
2526 /* check to see its' an eet file pointer */
2527 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2528 ((ef->mode != EET_FILE_MODE_READ) &&
2529 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2534 /* loop through all entries */
2535 num = (1 << ef->header->directory->size);
2536 for (i = 0; i < num; i++)
2538 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2545 } /* eet_num_entries */
2547 static Eet_File_Node *
2548 find_node_by_name(Eet_File *ef,
2554 /* get hash bucket this should be in */
2555 hash = _eet_hash_gen(name, ef->header->directory->size);
2557 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2559 if (eet_string_match(efn->name, name))
2564 } /* find_node_by_name */
2567 read_data_from_disk(Eet_File *ef,
2572 if (efn->offset < 0)
2577 if ((efn->offset + len) > ef->data_size)
2580 memcpy(buf, ef->data + efn->offset, len);
2587 /* seek to data location */
2588 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2592 len = fread(buf, len, 1, ef->readfp);
2596 } /* read_data_from_disk */