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 (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
644 for (i = 0; i < num; i++)
646 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
648 if (fwrite(efn->data, efn->size, 1, fp) != 1)
653 /* flush all write to the file. */
655 // this is going to really cause trouble. if ANYTHING this needs to go into a
656 // thread spawned off - but even then...
657 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
658 // manual pages at eachother, but ext4 broke behavior that has been in place
659 // for decades and that 1000's of apps rely on daily - that is that one operation
660 // to disk is committed to disk BEFORE following operations, so the fs retains
661 // a consistent state
662 // fsync(fileno(fp));
664 /* append signature if required */
667 error = eet_identity_sign(fp, ef->key);
668 if (error != EET_ERROR_NONE)
672 /* no more writes pending */
673 ef->writes_pending = 0;
677 return EET_ERROR_NONE;
684 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
686 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
688 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
690 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
692 default: error = EET_ERROR_WRITE_ERROR; break;
704 if (++eet_init_count != 1)
705 return eet_init_count;
709 fprintf(stderr, "Eet: Eina init failed");
710 return --eet_init_count;
713 _eet_log_dom_global = eina_log_domain_register("eet", EET_DEFAULT_LOG_COLOR);
714 if (_eet_log_dom_global < 0)
716 EINA_LOG_ERR("Eet Can not create a general log domain.");
720 if (!eet_node_init())
722 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
723 goto unregister_log_domain;
727 /* Before the library can be used, it must initialize itself if needed. */
728 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
730 gcry_check_version(NULL);
731 /* Disable warning messages about problems with the secure memory subsystem.
732 This command should be run right after gcry_check_version. */
733 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
734 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
735 enabling the use of secure memory. It also drops all extra privileges the
736 process has (i.e. if it is run as setuid (root)). If the argument nbytes
737 is 0, secure memory will be disabled. The minimum amount of secure memory
738 allocated is currently 16384 bytes; you may thus use a value of 1 to
739 request that default size. */
741 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
743 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
746 # ifdef EFL_HAVE_POSIX_THREADS
747 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
749 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
751 # endif /* ifdef EFL_HAVE_POSIX_THREADS */
752 if (gnutls_global_init())
755 #endif /* ifdef HAVE_GNUTLS */
757 ERR_load_crypto_strings();
758 OpenSSL_add_all_algorithms();
759 #endif /* ifdef HAVE_OPENSSL */
761 return eet_init_count;
767 unregister_log_domain:
768 eina_log_domain_unregister(_eet_log_dom_global);
769 _eet_log_dom_global = -1;
772 return --eet_init_count;
778 if (--eet_init_count != 0)
779 return eet_init_count;
784 gnutls_global_deinit();
785 #endif /* ifdef HAVE_GNUTLS */
789 #endif /* ifdef HAVE_OPENSSL */
790 eina_log_domain_unregister(_eet_log_dom_global);
791 _eet_log_dom_global = -1;
794 return eet_init_count;
798 eet_sync(Eet_File *ef)
802 if (eet_check_pointer(ef))
803 return EET_ERROR_BAD_OBJECT;
805 if ((ef->mode != EET_FILE_MODE_WRITE) &&
806 (ef->mode != EET_FILE_MODE_READ_WRITE))
807 return EET_ERROR_NOT_WRITABLE;
809 if (!ef->writes_pending)
810 return EET_ERROR_NONE;
814 ret = eet_flush2(ef);
827 * We need to compute the list of eet file to close separately from the cache,
828 * due to eet_close removing them from the cache after each call.
831 for (i = 0; i < eet_writers_num; i++)
833 if (eet_writers[i]->references <= 0)
837 for (i = 0; i < eet_readers_num; i++)
839 if (eet_readers[i]->references <= 0)
845 Eet_File **closelist = NULL;
847 closelist = alloca(num * sizeof(Eet_File *));
849 for (i = 0; i < eet_writers_num; i++)
851 if (eet_writers[i]->references <= 0)
853 closelist[num] = eet_writers[i];
854 eet_writers[i]->delete_me_now = 1;
859 for (i = 0; i < eet_readers_num; i++)
861 if (eet_readers[i]->references <= 0)
863 closelist[num] = eet_readers[i];
864 eet_readers[i]->delete_me_now = 1;
869 for (i = 0; i < num; i++)
871 eet_internal_close(closelist[i], EINA_TRUE);
876 } /* eet_clearcache */
878 /* FIXME: MMAP race condition in READ_WRITE_MODE */
880 eet_internal_read2(Eet_File *ef)
882 const int *data = (const int *)ef->data;
883 const char *start = (const char *)ef->data;
885 int num_directory_entries;
886 int bytes_directory_entries;
887 int num_dictionary_entries;
888 int bytes_dictionary_entries;
889 int signature_base_offset;
893 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
898 #define GET_INT(Value, Pointer, Index)\
900 Value = ntohl(*Pointer);\
902 Index += sizeof(int);\
905 /* get entries count and byte count */
906 GET_INT(num_directory_entries, data, idx);
907 /* get dictionary count and byte count */
908 GET_INT(num_dictionary_entries, data, idx);
910 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
911 num_directory_entries + EET_FILE2_HEADER_SIZE;
912 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
913 num_dictionary_entries;
915 /* we can't have <= 0 values here - invalid */
916 if (eet_test_close((num_directory_entries <= 0), ef))
919 /* we can't have more bytes directory and bytes in dictionaries than the size of the file */
920 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
924 /* allocate header */
925 ef->header = calloc(1, sizeof(Eet_File_Header));
926 if (eet_test_close(!ef->header, ef))
929 ef->header->magic = EET_MAGIC_FILE_HEADER;
931 /* allocate directory block in ram */
932 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
933 if (eet_test_close(!ef->header->directory, ef))
936 /* 8 bit hash table (256 buckets) */
937 ef->header->directory->size = 8;
938 /* allocate base hash table */
939 ef->header->directory->nodes =
940 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
941 if (eet_test_close(!ef->header->directory->nodes, ef))
944 signature_base_offset = 0;
946 /* actually read the directory block - all of it, into ram */
947 for (i = 0; i < num_directory_entries; ++i)
956 /* out directory block is inconsistent - we have oveerun our */
957 /* dynamic block buffer before we finished scanning dir entries */
958 efn = malloc(sizeof(Eet_File_Node));
959 if (eet_test_close(!efn, ef))
961 if (efn) free(efn); /* yes i know - we only get here if
962 * efn is null/0 -> trying to shut up
963 * warning tools like cppcheck */
967 /* get entrie header */
968 GET_INT(efn->offset, data, idx);
969 GET_INT(efn->size, data, idx);
970 GET_INT(efn->data_size, data, idx);
971 GET_INT(name_offset, data, idx);
972 GET_INT(name_size, data, idx);
973 GET_INT(flag, data, idx);
975 efn->compression = flag & 0x1 ? 1 : 0;
976 efn->ciphered = flag & 0x2 ? 1 : 0;
977 efn->alias = flag & 0x4 ? 1 : 0;
979 #define EFN_TEST(Test, Ef, Efn)\
980 if (eet_test_close(Test, Ef))\
986 /* check data pointer position */
987 EFN_TEST(!((efn->size > 0)
988 && (efn->offset + efn->size <= ef->data_size)
989 && (efn->offset > bytes_dictionary_entries +
990 bytes_directory_entries)), ef, efn);
992 /* check name position */
993 EFN_TEST(!((name_size > 0)
994 && (name_offset + name_size < ef->data_size)
995 && (name_offset >= bytes_dictionary_entries +
996 bytes_directory_entries)), ef, efn);
998 name = start + name_offset;
1000 /* check '\0' at the end of name string */
1001 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
1004 efn->name = (char *)name;
1005 efn->name_size = name_size;
1007 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1008 efn->next = ef->header->directory->nodes[hash];
1009 ef->header->directory->nodes[hash] = efn;
1011 /* read-only mode, so currently we have no data loaded */
1012 if (ef->mode == EET_FILE_MODE_READ)
1013 efn->data = NULL; /* read-write mode - read everything into ram */
1016 efn->data = malloc(efn->size);
1018 memcpy(efn->data, ef->data + efn->offset, efn->size);
1021 /* compute the possible position of a signature */
1022 if (signature_base_offset < efn->offset + efn->size)
1023 signature_base_offset = efn->offset + efn->size;
1028 if (num_dictionary_entries)
1030 const int *dico = (const int *)ef->data +
1031 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1032 EET_FILE2_HEADER_COUNT;
1035 if (eet_test_close((num_dictionary_entries *
1036 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1037 (bytes_dictionary_entries + bytes_directory_entries),
1041 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1042 if (eet_test_close(!ef->ed, ef))
1045 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1046 if (eet_test_close(!ef->ed->all, ef))
1049 ef->ed->count = num_dictionary_entries;
1050 ef->ed->total = num_dictionary_entries;
1051 ef->ed->start = start + bytes_dictionary_entries +
1052 bytes_directory_entries;
1053 ef->ed->end = ef->ed->start;
1055 for (j = 0; j < ef->ed->count; ++j)
1060 GET_INT(hash, dico, idx);
1061 GET_INT(offset, dico, idx);
1062 GET_INT(ef->ed->all[j].len, dico, idx);
1063 GET_INT(ef->ed->all[j].prev, dico, idx);
1064 GET_INT(ef->ed->all[j].next, dico, idx);
1066 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1067 So stick to int and check the value. */
1068 if (eet_test_close(hash & 0xFFFFFF00, ef))
1071 /* Check string position */
1072 if (eet_test_close(!((ef->ed->all[j].len > 0)
1074 (bytes_dictionary_entries +
1075 bytes_directory_entries))
1076 && (offset + ef->ed->all[j].len <
1077 ef->data_size)), ef))
1080 ef->ed->all[j].str = start + offset;
1082 if (ef->ed->all[j].str + ef->ed->all[j].len > ef->ed->end)
1083 ef->ed->end = ef->ed->all[j].str + ef->ed->all[j].len;
1085 /* Check '\0' at the end of the string */
1086 if (eet_test_close(ef->ed->all[j].str[ef->ed->all[j].len - 1] !=
1090 ef->ed->all[j].hash = hash;
1091 if (ef->ed->all[j].prev == -1)
1092 ef->ed->hash[hash] = j;
1094 /* compute the possible position of a signature */
1095 if (signature_base_offset < offset + ef->ed->all[j].len)
1096 signature_base_offset = offset + ef->ed->all[j].len;
1100 /* Check if the file is signed */
1101 ef->x509_der = NULL;
1102 ef->x509_length = 0;
1103 ef->signature = NULL;
1104 ef->signature_length = 0;
1106 if (signature_base_offset < ef->data_size)
1108 #ifdef HAVE_SIGNATURE
1109 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1110 signature_base_offset;
1111 ef->x509_der = eet_identity_check(ef->data,
1112 signature_base_offset,
1116 ef->data_size - signature_base_offset,
1118 &ef->signature_length,
1121 if (eet_test_close(!ef->x509_der, ef))
1124 #else /* ifdef HAVE_SIGNATURE */
1126 "This file could be signed but you didn't compile the necessary code to check the signature.");
1127 #endif /* ifdef HAVE_SIGNATURE */
1131 } /* eet_internal_read2 */
1133 #if EET_OLD_EET_FILE_FORMAT
1135 eet_internal_read1(Eet_File *ef)
1137 const unsigned char *dyn_buf = NULL;
1138 const unsigned char *p = NULL;
1145 "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.",
1148 /* build header table if read mode */
1151 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1154 #define EXTRACT_INT(Value, Pointer, Index)\
1157 memcpy(&tmp, Pointer + Index, sizeof(int));\
1158 Value = ntohl(tmp);\
1159 Index += sizeof(int);\
1162 /* get entries count and byte count */
1163 EXTRACT_INT(num_entries, ef->data, idx);
1164 EXTRACT_INT(byte_entries, ef->data, idx);
1166 /* we can't have <= 0 values here - invalid */
1167 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1170 /* we can't have more entires than minimum bytes for those! invalid! */
1171 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1174 /* check we will not outrun the file limit */
1175 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1179 /* allocate header */
1180 ef->header = calloc(1, sizeof(Eet_File_Header));
1181 if (eet_test_close(!ef->header, ef))
1184 ef->header->magic = EET_MAGIC_FILE_HEADER;
1186 /* allocate directory block in ram */
1187 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1188 if (eet_test_close(!ef->header->directory, ef))
1191 /* 8 bit hash table (256 buckets) */
1192 ef->header->directory->size = 8;
1193 /* allocate base hash table */
1194 ef->header->directory->nodes =
1195 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1196 if (eet_test_close(!ef->header->directory->nodes, ef))
1199 /* actually read the directory block - all of it, into ram */
1200 dyn_buf = ef->data + idx;
1202 /* parse directory block */
1205 for (i = 0; i < num_entries; i++)
1214 #define HEADER_SIZE (sizeof(int) * 5)
1216 /* out directory block is inconsistent - we have oveerun our */
1217 /* dynamic block buffer before we finished scanning dir entries */
1218 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1221 /* allocate all the ram needed for this stored node accounting */
1222 efn = malloc (sizeof(Eet_File_Node));
1223 if (eet_test_close(!efn, ef))
1225 if (efn) free(efn); /* yes i know - we only get here if
1226 * efn is null/0 -> trying to shut up
1227 * warning tools like cppcheck */
1231 /* get entrie header */
1232 EXTRACT_INT(efn->offset, p, indexn);
1233 EXTRACT_INT(efn->compression, p, indexn);
1234 EXTRACT_INT(efn->size, p, indexn);
1235 EXTRACT_INT(efn->data_size, p, indexn);
1236 EXTRACT_INT(name_size, p, indexn);
1238 efn->name_size = name_size;
1243 if (eet_test_close(efn->size <= 0, ef))
1249 /* invalid name_size */
1250 if (eet_test_close(name_size <= 0, ef))
1256 /* reading name would mean falling off end of dyn_buf - invalid */
1257 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1263 /* This code is useless if we dont want backward compatibility */
1265 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1268 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1272 efn->name = malloc(sizeof(char) * name_size + 1);
1273 if (eet_test_close(!efn->name, ef))
1279 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1280 efn->name[name_size] = 0;
1283 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1288 /* The only really useful peace of code for efn->name (no backward compatibility) */
1289 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1291 /* get hash bucket it should go in */
1292 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1293 efn->next = ef->header->directory->nodes[hash];
1294 ef->header->directory->nodes[hash] = efn;
1296 /* read-only mode, so currently we have no data loaded */
1297 if (ef->mode == EET_FILE_MODE_READ)
1298 efn->data = NULL; /* read-write mode - read everything into ram */
1301 data = malloc(efn->size);
1303 memcpy(data, ef->data + efn->offset, efn->size);
1309 p += HEADER_SIZE + name_size;
1312 } /* eet_internal_read1 */
1314 #endif /* if EET_OLD_EET_FILE_FORMAT */
1317 * this should only be called when the cache lock is already held
1318 * (We could drop this restriction if we add a parameter to eet_test_close
1319 * that indicates if the lock is held or not. For now it is easiest
1320 * to just require that it is always held.)
1323 eet_internal_read(Eet_File *ef)
1325 const int *data = (const int *)ef->data;
1327 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1330 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1333 switch (ntohl(*data))
1335 #if EET_OLD_EET_FILE_FORMAT
1336 case EET_MAGIC_FILE:
1337 return eet_internal_read1(ef);
1339 #endif /* if EET_OLD_EET_FILE_FORMAT */
1340 case EET_MAGIC_FILE2:
1341 return eet_internal_read2(ef);
1344 ef->delete_me_now = 1;
1345 eet_internal_close(ef, EINA_TRUE);
1350 } /* eet_internal_read */
1353 eet_internal_close(Eet_File *ef,
1358 /* check to see its' an eet file pointer */
1359 if (eet_check_pointer(ef))
1360 return EET_ERROR_BAD_OBJECT;
1367 /* if its still referenced - dont go any further */
1368 if (ef->references > 0)
1369 goto on_error; /* flush any writes */
1371 err = eet_flush2(ef);
1373 eet_identity_unref(ef->key);
1376 /* if not urgent to delete it - dont free it - leave it in cache */
1377 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1380 /* remove from cache */
1381 if (ef->mode == EET_FILE_MODE_READ)
1382 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1383 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1387 mode == EET_FILE_MODE_READ_WRITE))
1388 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1390 /* we can unlock the cache now */
1399 if (ef->header->directory)
1401 if (ef->header->directory->nodes)
1405 num = (1 << ef->header->directory->size);
1406 for (i = 0; i < num; i++)
1410 while ((efn = ef->header->directory->nodes[i]))
1415 ef->header->directory->nodes[i] = efn->next;
1423 free(ef->header->directory->nodes);
1426 free(ef->header->directory);
1432 eet_dictionary_free(ef->ed);
1438 munmap((void *)ef->data, ef->data_size);
1443 /* zero out ram for struct - caution tactic against stale memory use */
1444 memset(ef, 0, sizeof(Eet_File));
1454 return EET_ERROR_NONE;
1455 } /* eet_internal_close */
1458 eet_memopen_read(const void *data,
1463 if (!data || size == 0)
1466 ef = malloc (sizeof (Eet_File));
1474 ef->magic = EET_MAGIC_FILE;
1476 ef->mode = EET_FILE_MODE_READ;
1479 ef->delete_me_now = 1;
1482 ef->data_size = size;
1484 ef->sha1_length = 0;
1486 /* eet_internal_read expects the cache lock to be held when it is called */
1488 ef = eet_internal_read(ef);
1491 } /* eet_memopen_read */
1494 eet_open(const char *file,
1500 struct stat file_stat;
1505 /* find the current file handle in cache*/
1508 if (mode == EET_FILE_MODE_READ)
1510 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1515 ef->delete_me_now = 1;
1516 eet_internal_close(ef, EINA_TRUE);
1519 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1521 else if ((mode == EET_FILE_MODE_WRITE) ||
1522 (mode == EET_FILE_MODE_READ_WRITE))
1524 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1527 ef->delete_me_now = 1;
1529 eet_internal_close(ef, EINA_TRUE);
1532 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1535 /* try open the file based on mode */
1536 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1538 /* Prevent garbage in futur comparison. */
1539 file_stat.st_mtime = 0;
1541 fp = fopen(file, "rb");
1545 if (fstat(fileno(fp), &file_stat))
1550 memset(&file_stat, 0, sizeof(file_stat));
1555 if (file_stat.st_size < ((int)sizeof(int) * 3))
1560 memset(&file_stat, 0, sizeof(file_stat));
1566 if (!fp && mode == EET_FILE_MODE_READ)
1571 if (mode != EET_FILE_MODE_WRITE)
1574 memset(&file_stat, 0, sizeof(file_stat));
1581 ((file_stat.st_mtime != ef->mtime) ||
1582 (file_stat.st_size != ef->data_size)))
1584 ef->delete_me_now = 1;
1586 eet_internal_close(ef, EINA_TRUE);
1592 /* reference it up and return it */
1601 file_len = strlen(file) + 1;
1603 /* Allocate struct for eet file and have it zero'd out */
1604 ef = malloc(sizeof(Eet_File) + file_len);
1608 /* fill some of the members */
1612 ef->path = ((char *)ef) + sizeof(Eet_File);
1613 memcpy(ef->path, file, file_len);
1614 ef->magic = EET_MAGIC_FILE;
1618 ef->mtime = file_stat.st_mtime;
1619 ef->writes_pending = 0;
1620 ef->delete_me_now = 0;
1624 ef->sha1_length = 0;
1626 ef->ed = (mode == EET_FILE_MODE_WRITE)
1627 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1628 eet_dictionary_add() : NULL;
1631 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1634 /* if we can't open - bail out */
1635 if (eet_test_close(!ef->readfp, ef))
1638 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1639 /* if we opened for read or read-write */
1640 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1642 ef->data_size = file_stat.st_size;
1643 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1644 MAP_SHARED, fileno(ef->readfp), 0);
1645 if (eet_test_close((ef->data == MAP_FAILED), ef))
1648 ef = eet_internal_read(ef);
1655 if (ef->references == 1)
1657 if (ef->mode == EET_FILE_MODE_READ)
1658 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1660 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1661 (ef->mode == EET_FILE_MODE_READ_WRITE))
1662 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1674 eet_mode_get(Eet_File *ef)
1676 /* check to see its' an eet file pointer */
1677 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1678 return EET_FILE_MODE_INVALID;
1681 } /* eet_mode_get */
1684 eet_identity_x509(Eet_File *ef,
1691 *der_length = ef->x509_length;
1693 return ef->x509_der;
1694 } /* eet_identity_x509 */
1697 eet_identity_signature(Eet_File *ef,
1698 int *signature_length)
1703 if (signature_length)
1704 *signature_length = ef->signature_length;
1706 return ef->signature;
1707 } /* eet_identity_signature */
1710 eet_identity_sha1(Eet_File *ef,
1714 ef->sha1 = eet_identity_compute_sha1(ef->data,
1719 *sha1_length = ef->sha1_length;
1722 } /* eet_identity_sha1 */
1725 eet_identity_set(Eet_File *ef,
1728 Eet_Key *tmp = ef->key;
1731 return EET_ERROR_BAD_OBJECT;
1734 eet_identity_ref(ef->key);
1735 eet_identity_unref(tmp);
1737 /* flags that writes are pending */
1738 ef->writes_pending = 1;
1740 return EET_ERROR_NONE;
1741 } /* eet_identity_set */
1744 eet_close(Eet_File *ef)
1746 return eet_internal_close(ef, EINA_FALSE);
1750 eet_read_cipher(Eet_File *ef,
1753 const char *cipher_key)
1762 /* check to see its' an eet file pointer */
1763 if (eet_check_pointer(ef))
1769 if ((ef->mode != EET_FILE_MODE_READ) &&
1770 (ef->mode != EET_FILE_MODE_READ_WRITE))
1773 /* no header, return NULL */
1774 if (eet_check_header(ef))
1779 /* hunt hash bucket */
1780 efn = find_node_by_name(ef, name);
1784 /* get size (uncompressed, if compressed at all) */
1785 size = efn->data_size;
1788 data = malloc(size);
1792 /* uncompressed data */
1793 if (efn->compression == 0)
1795 void *data_deciphered = NULL;
1796 unsigned int data_deciphered_sz = 0;
1797 /* if we already have the data in ram... copy that */
1799 if (efn->ciphered && efn->size > size)
1802 data = realloc(data, efn->size);
1806 memcpy(data, efn->data, size);
1808 if (!read_data_from_disk(ef, efn, data, size))
1811 if (efn->ciphered && cipher_key)
1813 if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key),
1814 &data_deciphered, &data_deciphered_sz))
1816 if (data_deciphered)
1817 free(data_deciphered);
1823 data = data_deciphered;
1824 size = data_deciphered_sz;
1827 /* compressed data */
1830 void *tmp_data = NULL;
1831 void *data_deciphered = NULL;
1832 unsigned int data_deciphered_sz = 0;
1834 int compr_size = efn->size;
1837 /* if we already have the data in ram... copy that */
1839 tmp_data = efn->data;
1842 tmp_data = malloc(compr_size);
1848 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1855 if (efn->ciphered && cipher_key)
1857 if (eet_decipher(tmp_data, compr_size, cipher_key,
1858 strlen(cipher_key), &data_deciphered,
1859 &data_deciphered_sz))
1864 if (data_deciphered)
1865 free(data_deciphered);
1873 tmp_data = data_deciphered;
1874 compr_size = data_deciphered_sz;
1879 if (uncompress((Bytef *)data, &dlen,
1880 tmp_data, (uLongf)compr_size))
1898 if (data[size - 1] != '\0')
1901 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1908 /* fill in return values */
1918 } /* eet_read_cipher */
1921 eet_read(Eet_File *ef,
1925 return eet_read_cipher(ef, name, size_ret, NULL);
1929 eet_read_direct(Eet_File *ef,
1934 const char *data = NULL;
1940 /* check to see its' an eet file pointer */
1941 if (eet_check_pointer(ef))
1947 if ((ef->mode != EET_FILE_MODE_READ) &&
1948 (ef->mode != EET_FILE_MODE_READ_WRITE))
1951 /* no header, return NULL */
1952 if (eet_check_header(ef))
1957 /* hunt hash bucket */
1958 efn = find_node_by_name(ef, name);
1962 if (efn->offset < 0 && !efn->data)
1965 /* get size (uncompressed, if compressed at all) */
1966 size = efn->data_size;
1970 data = efn->data ? efn->data : ef->data + efn->offset;
1972 /* handle alias case */
1973 if (efn->compression)
1976 int compr_size = efn->size;
1979 tmp = alloca(sizeof (compr_size));
1982 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1983 (uLongf)compr_size))
1986 if (tmp[compr_size - 1] != '\0')
1991 return eet_read_direct(ef, tmp, size_ret);
1997 if (data[size - 1] != '\0')
2002 return eet_read_direct(ef, data, size_ret);
2005 /* uncompressed data */
2006 if (efn->compression == 0
2007 && efn->ciphered == 0)
2008 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
2012 /* fill in return values */
2023 } /* eet_read_direct */
2026 eet_alias(Eet_File *ef,
2028 const char *destination,
2033 Eina_Bool exists_already = EINA_FALSE;
2037 /* check to see its' an eet file pointer */
2038 if (eet_check_pointer(ef))
2041 if ((!name) || (!destination))
2044 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2045 (ef->mode != EET_FILE_MODE_READ_WRITE))
2052 /* allocate header */
2053 ef->header = calloc(1, sizeof(Eet_File_Header));
2057 ef->header->magic = EET_MAGIC_FILE_HEADER;
2058 /* allocate directory block in ram */
2059 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2060 if (!ef->header->directory)
2067 /* 8 bit hash table (256 buckets) */
2068 ef->header->directory->size = 8;
2069 /* allocate base hash table */
2070 ef->header->directory->nodes =
2071 calloc(1, sizeof(Eet_File_Node *) *
2072 (1 << ef->header->directory->size));
2073 if (!ef->header->directory->nodes)
2075 free(ef->header->directory);
2081 /* figure hash bucket */
2082 hash = _eet_hash_gen(name, ef->header->directory->size);
2085 12 + (((strlen(destination) + 1) * 101) / 100)
2086 : strlen(destination) + 1;
2088 data2 = malloc(data_size);
2092 /* if we want to compress */
2097 /* compress the data with max compression */
2098 buflen = (uLongf)data_size;
2099 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2100 (uLong)strlen(destination) + 1,
2101 Z_BEST_COMPRESSION) != Z_OK)
2107 /* record compressed chunk size */
2108 data_size = (int)buflen;
2109 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2112 data_size = strlen(destination) + 1;
2118 data3 = realloc(data2, data_size);
2125 memcpy(data2, destination, data_size);
2127 /* Does this node already exist? */
2128 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2131 if ((efn->name) && (eet_string_match(efn->name, name)))
2136 efn->compression = !!comp;
2137 efn->size = data_size;
2138 efn->data_size = strlen(destination) + 1;
2141 exists_already = EINA_TRUE;
2145 if (!exists_already)
2147 efn = malloc(sizeof(Eet_File_Node));
2154 efn->name = strdup(name);
2155 efn->name_size = strlen(efn->name) + 1;
2158 efn->next = ef->header->directory->nodes[hash];
2159 ef->header->directory->nodes[hash] = efn;
2163 efn->compression = !!comp;
2164 efn->size = data_size;
2165 efn->data_size = strlen(destination) + 1;
2169 /* flags that writes are pending */
2170 ef->writes_pending = 1;
2181 eet_write_cipher(Eet_File *ef,
2186 const char *cipher_key)
2190 int exists_already = 0;
2194 /* check to see its' an eet file pointer */
2195 if (eet_check_pointer(ef))
2198 if ((!name) || (!data) || (size <= 0))
2201 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2202 (ef->mode != EET_FILE_MODE_READ_WRITE))
2209 /* allocate header */
2210 ef->header = calloc(1, sizeof(Eet_File_Header));
2214 ef->header->magic = EET_MAGIC_FILE_HEADER;
2215 /* allocate directory block in ram */
2216 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2217 if (!ef->header->directory)
2224 /* 8 bit hash table (256 buckets) */
2225 ef->header->directory->size = 8;
2226 /* allocate base hash table */
2227 ef->header->directory->nodes =
2228 calloc(1, sizeof(Eet_File_Node *) *
2229 (1 << ef->header->directory->size));
2230 if (!ef->header->directory->nodes)
2232 free(ef->header->directory);
2238 /* figure hash bucket */
2239 hash = _eet_hash_gen(name, ef->header->directory->size);
2241 data_size = comp ? 12 + ((size * 101) / 100) : size;
2243 if (comp || !cipher_key)
2245 data2 = malloc(data_size);
2250 /* if we want to compress */
2255 /* compress the data with max compression */
2256 buflen = (uLongf)data_size;
2257 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2258 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2264 /* record compressed chunk size */
2265 data_size = (int)buflen;
2266 if (data_size < 0 || data_size >= size)
2275 data3 = realloc(data2, data_size);
2283 void *data_ciphered = NULL;
2284 unsigned int data_ciphered_sz = 0;
2287 tmp = comp ? data2 : data;
2288 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2289 &data_ciphered, &data_ciphered_sz))
2294 data2 = data_ciphered;
2295 data_size = data_ciphered_sz;
2300 free(data_ciphered);
2307 memcpy(data2, data, size);
2309 /* Does this node already exist? */
2310 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2313 if ((efn->name) && (eet_string_match(efn->name, name)))
2317 efn->ciphered = cipher_key ? 1 : 0;
2318 efn->compression = !!comp;
2319 efn->size = data_size;
2320 efn->data_size = size;
2327 if (!exists_already)
2329 efn = malloc(sizeof(Eet_File_Node));
2336 efn->name = strdup(name);
2337 efn->name_size = strlen(efn->name) + 1;
2340 efn->next = ef->header->directory->nodes[hash];
2341 ef->header->directory->nodes[hash] = efn;
2344 efn->ciphered = cipher_key ? 1 : 0;
2345 efn->compression = !!comp;
2346 efn->size = data_size;
2347 efn->data_size = size;
2351 /* flags that writes are pending */
2352 ef->writes_pending = 1;
2359 } /* eet_write_cipher */
2362 eet_write(Eet_File *ef,
2368 return eet_write_cipher(ef, name, data, size, comp, NULL);
2372 eet_delete(Eet_File *ef,
2376 Eet_File_Node *pefn;
2378 int exists_already = 0;
2380 /* check to see its' an eet file pointer */
2381 if (eet_check_pointer(ef))
2387 /* deleting keys is only possible in RW or WRITE mode */
2388 if (ef->mode == EET_FILE_MODE_READ)
2391 if (eet_check_header(ef))
2396 /* figure hash bucket */
2397 hash = _eet_hash_gen(name, ef->header->directory->size);
2399 /* Does this node already exist? */
2400 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2402 pefn = efn, efn = efn->next)
2405 if (eet_string_match(efn->name, name))
2411 ef->header->directory->nodes[hash] = efn->next;
2413 pefn->next = efn->next;
2423 /* flags that writes are pending */
2425 ef->writes_pending = 1;
2429 /* update access time */
2430 return exists_already;
2433 EAPI Eet_Dictionary *
2434 eet_dictionary_get(Eet_File *ef)
2436 if (eet_check_pointer(ef))
2440 } /* eet_dictionary_get */
2443 eet_list(Eet_File *ef,
2448 char **list_ret = NULL;
2450 int list_count_alloc = 0;
2453 /* check to see its' an eet file pointer */
2454 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2456 ((ef->mode != EET_FILE_MODE_READ) &&
2457 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2465 if (!strcmp(glob, "*"))
2470 /* loop through all entries */
2471 num = (1 << ef->header->directory->size);
2472 for (i = 0; i < num; i++)
2474 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2476 /* if the entry matches the input glob
2477 * check for * explicitly, because on some systems, * isn't well
2480 if ((!glob) || !fnmatch(glob, efn->name, 0))
2482 /* add it to our list */
2485 /* only realloc in 32 entry chunks */
2486 if (list_count > list_count_alloc)
2488 char **new_list = NULL;
2490 list_count_alloc += 64;
2492 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2500 list_ret = new_list;
2503 /* put pointer of name string in */
2504 list_ret[list_count - 1] = efn->name;
2511 /* return count and list */
2513 *count_ret = list_count;
2527 eet_num_entries(Eet_File *ef)
2529 int i, num, ret = 0;
2532 /* check to see its' an eet file pointer */
2533 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2534 ((ef->mode != EET_FILE_MODE_READ) &&
2535 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2540 /* loop through all entries */
2541 num = (1 << ef->header->directory->size);
2542 for (i = 0; i < num; i++)
2544 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2551 } /* eet_num_entries */
2553 static Eet_File_Node *
2554 find_node_by_name(Eet_File *ef,
2560 /* get hash bucket this should be in */
2561 hash = _eet_hash_gen(name, ef->header->directory->size);
2563 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2565 if (eet_string_match(efn->name, name))
2570 } /* find_node_by_name */
2573 read_data_from_disk(Eet_File *ef,
2578 if (efn->offset < 0)
2583 if ((efn->offset + len) > ef->data_size)
2586 memcpy(buf, ef->data + efn->offset, len);
2593 /* seek to data location */
2594 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2598 len = fread(buf, len, 1, ef->readfp);
2602 } /* read_data_from_disk */