2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
7 #endif /* ifdef HAVE_CONFIG_H */
11 #elif defined __GNUC__
12 # define alloca __builtin_alloca
14 # define alloca __alloca
15 #elif defined _MSC_VER
17 # define alloca _alloca
18 #else /* ifdef HAVE_ALLOCA_H */
22 # endif /* ifdef __cplusplus */
23 void * alloca (size_t);
24 #endif /* ifdef HAVE_ALLOCA_H */
27 # include <winsock2.h>
28 #endif /* ifdef _WIN32 */
32 #include <sys/types.h>
43 #endif /* ifndef _MSC_VER */
45 #ifdef HAVE_NETINET_IN_H
46 # include <netinet/in.h>
47 #endif /* ifdef HAVE_NETINET_IN_H */
51 #endif /* ifdef HAVE_EVIL */
54 # include <gnutls/gnutls.h>
56 #endif /* ifdef HAVE_GNUTLS */
59 # include <openssl/err.h>
60 # include <openssl/evp.h>
61 #endif /* ifdef HAVE_OPENSSL */
63 #ifdef EFL_HAVE_POSIX_THREADS
66 GCRY_THREAD_OPTION_PTHREAD_IMPL;
67 # endif /* ifdef HAVE_GNUTLS */
68 #endif /* ifdef EFL_HAVE_POSIX_THREADS */
73 #include "Eet_private.h"
75 static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
76 EAPI Eet_Version *eet_version = &_version;
80 #endif /* ifdef HAVE_REALPATH */
82 #define EET_MAGIC_FILE 0x1ee7ff00
83 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
85 #define EET_MAGIC_FILE2 0x1ee70f42
87 typedef struct _Eet_File_Header Eet_File_Header;
88 typedef struct _Eet_File_Node Eet_File_Node;
89 typedef struct _Eet_File_Directory Eet_File_Directory;
95 Eet_File_Header * header;
98 const unsigned char *data;
99 const void * x509_der;
100 const void * signature;
110 unsigned int signature_length;
115 #ifdef EFL_HAVE_THREADS
116 # ifdef EFL_HAVE_POSIX_THREADS
117 pthread_mutex_t file_lock;
118 # else /* ifdef EFL_HAVE_POSIX_THREADS */
120 # endif /* ifdef EFL_HAVE_POSIX_THREADS */
121 #endif /* ifdef EFL_HAVE_THREADS */
123 unsigned char writes_pending : 1;
124 unsigned char delete_me_now : 1;
127 struct _Eet_File_Header
130 Eet_File_Directory *directory;
133 struct _Eet_File_Directory
136 Eet_File_Node **nodes;
139 struct _Eet_File_Node
143 Eet_File_Node *next; /* FIXME: make buckets linked lists */
146 int dictionary_offset;
153 unsigned char free_name : 1;
154 unsigned char compression : 1;
155 unsigned char ciphered : 1;
156 unsigned char alias : 1;
161 /* NB: all int's are stored in network byte order on disk */
163 int magic; /* magic number ie 0x1ee7ff00 */
164 int num_directory_entries; /* number of directory entries to follow */
165 int bytes_directory_entries; /* bytes of directory entries to follow */
168 int offset; /* bytes offset into file for data chunk */
169 int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
170 int size; /* size of the data chunk */
171 int data_size; /* size of the (uncompressed) data chunk */
172 int name_size; /* length in bytes of the name field */
173 char name[name_size]; /* name string (variable length) and \0 terminated */
174 } directory[num_directory_entries];
175 /* and now startes the data stream... */
180 /* NB: all int's are stored in network byte order on disk */
182 int magic; /* magic number ie 0x1ee70f42 */
183 int num_directory_entries; /* number of directory entries to follow */
184 int num_dictionary_entries; /* number of dictionary entries to follow */
187 int data_offset; /* bytes offset into file for data chunk */
188 int size; /* size of the data chunk */
189 int data_size; /* size of the (uncompressed) data chunk */
190 int name_offset; /* bytes offset into file for name string */
191 int name_size; /* length in bytes of the name field */
192 int flags; /* bit flags - for now:
193 bit 0 => compresion on/off
194 bit 1 => ciphered on/off
197 } directory[num_directory_entries];
205 } dictionary[num_dictionary_entries];
206 /* now start the string stream. */
207 /* and right after them the data stream. */
208 int magic_sign; /* Optional, only if the eet file is signed. */
209 int signature_length; /* Signature length. */
210 int x509_length; /* Public certificate that signed the file. */
211 char signature[signature_length]; /* The signature. */
212 char x509[x509_length]; /* The public certificate. */
215 #define EET_FILE2_HEADER_COUNT 3
216 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
217 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
219 #define EET_FILE2_HEADER_SIZE (sizeof(int) *\
220 EET_FILE2_HEADER_COUNT)
221 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) *\
222 EET_FILE2_DIRECTORY_ENTRY_COUNT)
223 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) *\
224 EET_FILE2_DICTIONARY_ENTRY_COUNT)
226 /* prototypes of internal calls */
227 static Eet_File * eet_cache_find(const char *path,
230 static void eet_cache_add(Eet_File * ef,
234 static void eet_cache_del(Eet_File * ef,
238 static int eet_string_match(const char *s1, const char *s2);
240 static Eet_Error eet_flush(Eet_File *ef);
242 static Eet_Error eet_flush2(Eet_File *ef);
243 static Eet_File_Node * find_node_by_name(Eet_File *ef, const char *name);
244 static int read_data_from_disk(Eet_File * ef,
249 static Eet_Error eet_internal_close(Eet_File *ef, Eina_Bool locked);
251 #ifdef EFL_HAVE_THREADS
253 # ifdef EFL_HAVE_POSIX_THREADS
255 static pthread_mutex_t eet_cache_lock = PTHREAD_MUTEX_INITIALIZER;
257 # define LOCK_CACHE pthread_mutex_lock(&eet_cache_lock)
258 # define UNLOCK_CACHE pthread_mutex_unlock(&eet_cache_lock)
260 # define INIT_FILE(File) pthread_mutex_init(&File->file_lock, NULL)
261 # define LOCK_FILE(File) pthread_mutex_lock(&File->file_lock)
262 # define UNLOCK_FILE(File) pthread_mutex_unlock(&File->file_lock)
263 # define DESTROY_FILE(File) pthread_mutex_destroy(&File->file_lock)
265 # else /* EFL_HAVE_WIN32_THREADS */
267 static HANDLE eet_cache_lock = NULL;
269 # define LOCK_CACHE WaitForSingleObject(eet_cache_lock, INFINITE)
270 # define UNLOCK_CACHE ReleaseMutex(eet_cache_lock)
272 # define INIT_FILE(File) File->file_lock = CreateMutex(NULL, FALSE, NULL)
273 # define LOCK_FILE(File) WaitForSingleObject(File->file_lock, INFINITE)
274 # define UNLOCK_FILE(File) ReleaseMutex(File->file_lock)
275 # define DESTROY_FILE(File) CloseHandle(File->file_lock)
277 # endif /* EFL_HAVE_WIN32_THREADS */
279 #else /* ifdef EFL_HAVE_THREADS */
281 # define LOCK_CACHE do {} while (0)
282 # define UNLOCK_CACHE do {} while (0)
284 # define INIT_FILE(File) do {} while (0)
285 # define LOCK_FILE(File) do {} while (0)
286 # define UNLOCK_FILE(File) do {} while (0)
287 # define DESTROY_FILE(File) do {} while (0)
289 #endif /* EFL_HAVE_THREADS */
291 /* cache. i don't expect this to ever be large, so arrays will do */
292 static int eet_writers_num = 0;
293 static int eet_writers_alloc = 0;
294 static Eet_File **eet_writers = NULL;
295 static int eet_readers_num = 0;
296 static int eet_readers_alloc = 0;
297 static Eet_File **eet_readers = NULL;
298 static int eet_init_count = 0;
300 /* log domain variable */
301 int _eet_log_dom_global = -1;
303 /* Check to see its' an eet file pointer */
305 eet_check_pointer(const Eet_File *ef)
307 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
311 } /* eet_check_pointer */
314 eet_check_header(const Eet_File *ef)
319 if (!ef->header->directory)
323 } /* eet_check_header */
326 eet_test_close(int test,
331 ef->delete_me_now = 1;
332 eet_internal_close(ef, EINA_TRUE);
336 } /* eet_test_close */
338 /* find an eet file in the currently in use cache */
340 eet_cache_find(const char *path,
347 for (i = 0; i < cache_num; i++)
349 /* if matches real path - return it */
350 if (eet_string_match(cache[i]->path, path))
351 if (!cache[i]->delete_me_now)
358 } /* eet_cache_find */
360 /* add to end of cache */
361 /* this should only be called when the cache lock is already held */
363 eet_cache_add(Eet_File * ef,
368 Eet_File **new_cache;
372 new_cache_num = *cache_num;
373 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
375 Eet_File *del_ef = NULL;
379 for (i = 0; i < new_cache_num; i++)
381 if (new_cache[i]->references == 0)
383 del_ef = new_cache[i];
390 del_ef->delete_me_now = 1;
391 eet_internal_close(del_ef, EINA_TRUE);
396 new_cache_num = *cache_num;
397 new_cache_alloc = *cache_alloc;
399 if (new_cache_num > new_cache_alloc)
401 new_cache_alloc += 16;
402 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
405 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
410 new_cache[new_cache_num - 1] = ef;
412 *cache_num = new_cache_num;
413 *cache_alloc = new_cache_alloc;
414 } /* eet_cache_add */
416 /* delete from cache */
417 /* this should only be called when the cache lock is already held */
419 eet_cache_del(Eet_File * ef,
424 Eet_File **new_cache;
425 int new_cache_num, new_cache_alloc;
429 new_cache_num = *cache_num;
430 new_cache_alloc = *cache_alloc;
431 if (new_cache_num <= 0)
434 for (i = 0; i < new_cache_num; i++)
436 if (new_cache[i] == ef)
440 if (i >= new_cache_num)
444 for (j = i; j < new_cache_num; j++)
445 new_cache[j] = new_cache[j + 1];
447 if (new_cache_num <= (new_cache_alloc - 16))
449 new_cache_alloc -= 16;
450 if (new_cache_num > 0)
452 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
455 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
467 *cache_num = new_cache_num;
468 *cache_alloc = new_cache_alloc;
469 } /* eet_cache_del */
471 /* internal string match. null friendly, catches same ptr */
473 eet_string_match(const char *s1,
476 /* both null- no match */
483 return (!strcmp(s1, s2));
484 } /* eet_string_match */
486 /* flush out writes to a v2 eet file */
488 eet_flush2(Eet_File *ef)
492 Eet_Error error = EET_ERROR_NONE;
493 int head[EET_FILE2_HEADER_COUNT];
494 int num_directory_entries = 0;
495 int num_dictionary_entries = 0;
496 int bytes_directory_entries = 0;
497 int bytes_dictionary_entries = 0;
498 int bytes_strings = 0;
500 int strings_offset = 0;
505 if (eet_check_pointer(ef))
506 return EET_ERROR_BAD_OBJECT;
508 if (eet_check_header(ef))
509 return EET_ERROR_EMPTY;
511 if (!ef->writes_pending)
512 return EET_ERROR_NONE;
514 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
515 || (ef->mode == EET_FILE_MODE_WRITE))
519 /* opening for write - delete old copy of file right away */
521 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
522 fp = fdopen(fd, "wb");
524 return EET_ERROR_NOT_WRITABLE;
526 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
529 return EET_ERROR_NOT_WRITABLE;
531 /* calculate string base offset and data base offset */
532 num = (1 << ef->header->directory->size);
533 for (i = 0; i < num; ++i)
535 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
537 num_directory_entries++;
538 bytes_strings += strlen(efn->name) + 1;
543 num_dictionary_entries = ef->ed->count;
545 for (i = 0; i < num_dictionary_entries; ++i)
546 bytes_strings += ef->ed->all[i].len;
549 /* calculate section bytes size */
550 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
551 num_directory_entries + EET_FILE2_HEADER_SIZE;
552 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
553 num_dictionary_entries;
555 /* calculate per entry offset */
556 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
557 data_offset = bytes_directory_entries + bytes_dictionary_entries +
560 for (i = 0; i < num; ++i)
562 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
564 efn->offset = data_offset;
565 data_offset += efn->size;
567 efn->name_offset = strings_offset;
568 strings_offset += efn->name_size;
572 /* calculate dictionary strings offset */
574 ef->ed->offset = strings_offset;
576 /* go thru and write the header */
577 head[0] = (int)htonl((unsigned int)EET_MAGIC_FILE2);
578 head[1] = (int)htonl((unsigned int)num_directory_entries);
579 head[2] = (int)htonl((unsigned int)num_dictionary_entries);
581 fseek(fp, 0, SEEK_SET);
582 if (fwrite(head, sizeof (head), 1, fp) != 1)
585 /* write directories entry */
586 for (i = 0; i < num; i++)
588 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
591 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
593 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
595 ibuf[0] = (int)htonl((unsigned int)efn->offset);
596 ibuf[1] = (int)htonl((unsigned int)efn->size);
597 ibuf[2] = (int)htonl((unsigned int)efn->data_size);
598 ibuf[3] = (int)htonl((unsigned int)efn->name_offset);
599 ibuf[4] = (int)htonl((unsigned int)efn->name_size);
600 ibuf[5] = (int)htonl((unsigned int)flag);
602 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
607 /* write dictionnary */
610 int offset = strings_offset;
612 for (j = 0; j < ef->ed->count; ++j)
614 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
616 sbuf[0] = (int)htonl((unsigned int)ef->ed->all[j].hash);
617 sbuf[1] = (int)htonl((unsigned int)offset);
618 sbuf[2] = (int)htonl((unsigned int)ef->ed->all[j].len);
619 sbuf[3] = (int)htonl((unsigned int)ef->ed->all[j].prev);
620 sbuf[4] = (int)htonl((unsigned int)ef->ed->all[j].next);
622 offset += ef->ed->all[j].len;
624 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
629 /* write directories name */
630 for (i = 0; i < num; i++)
632 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
634 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
641 for (j = 0; j < ef->ed->count; ++j)
643 if (ef->ed->all[j].str)
645 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
648 else if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, fp) != 1)
653 for (i = 0; i < num; i++)
655 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
657 if (fwrite(efn->data, efn->size, 1, fp) != 1)
662 /* flush all write to the file. */
664 // this is going to really cause trouble. if ANYTHING this needs to go into a
665 // thread spawned off - but even then...
666 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
667 // manual pages at eachother, but ext4 broke behavior that has been in place
668 // for decades and that 1000's of apps rely on daily - that is that one operation
669 // to disk is committed to disk BEFORE following operations, so the fs retains
670 // a consistent state
671 // fsync(fileno(fp));
673 /* append signature if required */
676 error = eet_identity_sign(fp, ef->key);
677 if (error != EET_ERROR_NONE)
681 /* no more writes pending */
682 ef->writes_pending = 0;
686 return EET_ERROR_NONE;
693 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
695 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
697 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
699 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
701 default: error = EET_ERROR_WRITE_ERROR; break;
713 if (++eet_init_count != 1)
714 return eet_init_count;
718 fprintf(stderr, "Eet: Eina init failed");
719 return --eet_init_count;
722 _eet_log_dom_global = eina_log_domain_register("Eet", EET_DEFAULT_LOG_COLOR);
723 if (_eet_log_dom_global < 0)
725 EINA_LOG_ERR("Eet Can not create a general log domain.");
729 if (!eet_node_init())
731 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
732 goto unregister_log_domain;
736 /* Before the library can be used, it must initialize itself if needed. */
737 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
739 gcry_check_version(NULL);
740 /* Disable warning messages about problems with the secure memory subsystem.
741 This command should be run right after gcry_check_version. */
742 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
743 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
744 enabling the use of secure memory. It also drops all extra privileges the
745 process has (i.e. if it is run as setuid (root)). If the argument nbytes
746 is 0, secure memory will be disabled. The minimum amount of secure memory
747 allocated is currently 16384 bytes; you may thus use a value of 1 to
748 request that default size. */
750 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
752 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
755 #ifdef EFL_HAVE_POSIX_THREADS
756 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
758 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
760 #endif /* ifdef EFL_HAVE_POSIX_THREADS */
761 if (gnutls_global_init())
764 #endif /* ifdef HAVE_GNUTLS */
766 ERR_load_crypto_strings();
767 OpenSSL_add_all_algorithms();
768 #endif /* ifdef HAVE_OPENSSL */
770 return eet_init_count;
774 unregister_log_domain:
775 eina_log_domain_unregister(_eet_log_dom_global);
776 _eet_log_dom_global = -1;
779 return --eet_init_count;
785 if (--eet_init_count != 0)
786 return eet_init_count;
791 gnutls_global_deinit();
792 #endif /* ifdef HAVE_GNUTLS */
796 #endif /* ifdef HAVE_OPENSSL */
797 eina_log_domain_unregister(_eet_log_dom_global);
798 _eet_log_dom_global = -1;
801 return eet_init_count;
805 eet_sync(Eet_File *ef)
809 if (eet_check_pointer(ef))
810 return EET_ERROR_BAD_OBJECT;
812 if ((ef->mode != EET_FILE_MODE_WRITE) &&
813 (ef->mode != EET_FILE_MODE_READ_WRITE))
814 return EET_ERROR_NOT_WRITABLE;
816 if (!ef->writes_pending)
817 return EET_ERROR_NONE;
821 ret = eet_flush2(ef);
834 * We need to compute the list of eet file to close separately from the cache,
835 * due to eet_close removing them from the cache after each call.
838 for (i = 0; i < eet_writers_num; i++)
840 if (eet_writers[i]->references <= 0)
844 for (i = 0; i < eet_readers_num; i++)
846 if (eet_readers[i]->references <= 0)
852 Eet_File **closelist = NULL;
854 closelist = alloca(num * sizeof(Eet_File *));
856 for (i = 0; i < eet_writers_num; i++)
858 if (eet_writers[i]->references <= 0)
860 closelist[num] = eet_writers[i];
861 eet_writers[i]->delete_me_now = 1;
866 for (i = 0; i < eet_readers_num; i++)
868 if (eet_readers[i]->references <= 0)
870 closelist[num] = eet_readers[i];
871 eet_readers[i]->delete_me_now = 1;
876 for (i = 0; i < num; i++)
878 eet_internal_close(closelist[i], EINA_TRUE);
883 } /* eet_clearcache */
885 /* FIXME: MMAP race condition in READ_WRITE_MODE */
887 eet_internal_read2(Eet_File *ef)
889 const int *data = (const int *)ef->data;
890 const char *start = (const char *)ef->data;
892 int num_directory_entries;
893 int bytes_directory_entries;
894 int num_dictionary_entries;
895 int bytes_dictionary_entries;
896 int signature_base_offset;
900 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
905 #define GET_INT(Value, Pointer, Index)\
907 Value = ntohl(*Pointer);\
909 Index += sizeof(int);\
912 /* get entries count and byte count */
913 GET_INT(num_directory_entries, data, idx);
914 /* get dictionary count and byte count */
915 GET_INT(num_dictionary_entries, data, idx);
917 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
918 num_directory_entries + EET_FILE2_HEADER_SIZE;
919 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
920 num_dictionary_entries;
922 /* we cant have <= 0 values here - invalid */
923 if (eet_test_close((num_directory_entries <= 0), ef))
926 /* we cant have more bytes directory and bytes in dictionaries than the size of the file */
927 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
931 /* allocate header */
932 ef->header = calloc(1, sizeof(Eet_File_Header));
933 if (eet_test_close(!ef->header, ef))
936 ef->header->magic = EET_MAGIC_FILE_HEADER;
938 /* allocate directory block in ram */
939 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
940 if (eet_test_close(!ef->header->directory, ef))
943 /* 8 bit hash table (256 buckets) */
944 ef->header->directory->size = 8;
945 /* allocate base hash table */
946 ef->header->directory->nodes =
947 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
948 if (eet_test_close(!ef->header->directory->nodes, ef))
951 signature_base_offset = 0;
953 /* actually read the directory block - all of it, into ram */
954 for (i = 0; i < num_directory_entries; ++i)
963 /* out directory block is inconsistent - we have oveerun our */
964 /* dynamic block buffer before we finished scanning dir entries */
965 efn = malloc (sizeof(Eet_File_Node));
966 if (eet_test_close(!efn, ef))
969 /* get entrie header */
970 GET_INT(efn->offset, data, idx);
971 GET_INT(efn->size, data, idx);
972 GET_INT(efn->data_size, data, idx);
973 GET_INT(name_offset, data, idx);
974 GET_INT(name_size, data, idx);
975 GET_INT(flag, data, idx);
977 efn->compression = flag & 0x1 ? 1 : 0;
978 efn->ciphered = flag & 0x2 ? 1 : 0;
979 efn->alias = flag & 0x4 ? 1 : 0;
981 #define EFN_TEST(Test, Ef, Efn)\
982 if (eet_test_close(Test, Ef))\
988 /* check data pointer position */
989 EFN_TEST(!((efn->size > 0)
990 && (efn->offset + efn->size <= ef->data_size)
991 && (efn->offset > bytes_dictionary_entries +
992 bytes_directory_entries)), ef, efn);
994 /* check name position */
995 EFN_TEST(!((name_size > 0)
996 && (name_offset + name_size < ef->data_size)
997 && (name_offset >= bytes_dictionary_entries +
998 bytes_directory_entries)), ef, efn);
1000 name = start + name_offset;
1002 /* check '\0' at the end of name string */
1003 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
1006 efn->name = (char *)name;
1007 efn->name_size = name_size;
1009 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1010 efn->next = ef->header->directory->nodes[hash];
1011 ef->header->directory->nodes[hash] = efn;
1013 /* read-only mode, so currently we have no data loaded */
1014 if (ef->mode == EET_FILE_MODE_READ)
1015 efn->data = NULL; /* read-write mode - read everything into ram */
1018 efn->data = malloc(efn->size);
1020 memcpy(efn->data, ef->data + efn->offset, efn->size);
1023 /* compute the possible position of a signature */
1024 if (signature_base_offset < efn->offset + efn->size)
1025 signature_base_offset = efn->offset + efn->size;
1030 if (num_dictionary_entries)
1032 const int *dico = (const int *)ef->data +
1033 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1034 EET_FILE2_HEADER_COUNT;
1037 if (eet_test_close((num_dictionary_entries *
1038 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1039 (bytes_dictionary_entries + bytes_directory_entries),
1043 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1044 if (eet_test_close(!ef->ed, ef))
1047 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1048 if (eet_test_close(!ef->ed->all, ef))
1051 ef->ed->count = num_dictionary_entries;
1052 ef->ed->total = num_dictionary_entries;
1053 ef->ed->start = start + bytes_dictionary_entries +
1054 bytes_directory_entries;
1055 ef->ed->end = ef->ed->start;
1057 for (j = 0; j < ef->ed->count; ++j)
1062 GET_INT(hash, dico, idx);
1063 GET_INT(offset, dico, idx);
1064 GET_INT(ef->ed->all[j].len, dico, idx);
1065 GET_INT(ef->ed->all[j].prev, dico, idx);
1066 GET_INT(ef->ed->all[j].next, dico, idx);
1068 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1069 So stick to int and check the value. */
1070 if (eet_test_close(hash & 0xFFFFFF00, ef))
1073 /* Check string position */
1074 if (eet_test_close(!((ef->ed->all[j].len > 0)
1076 (bytes_dictionary_entries +
1077 bytes_directory_entries))
1078 && (offset + ef->ed->all[j].len <
1079 ef->data_size)), ef))
1082 ef->ed->all[j].mmap = start + offset;
1083 ef->ed->all[j].str = NULL;
1085 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
1086 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
1088 /* Check '\0' at the end of the string */
1089 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] !=
1093 ef->ed->all[j].hash = hash;
1094 if (ef->ed->all[j].prev == -1)
1095 ef->ed->hash[hash] = j;
1097 /* compute the possible position of a signature */
1098 if (signature_base_offset < offset + ef->ed->all[j].len)
1099 signature_base_offset = offset + ef->ed->all[j].len;
1103 /* Check if the file is signed */
1104 ef->x509_der = NULL;
1105 ef->x509_length = 0;
1106 ef->signature = NULL;
1107 ef->signature_length = 0;
1109 if (signature_base_offset < ef->data_size)
1111 #ifdef HAVE_SIGNATURE
1112 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1113 signature_base_offset;
1114 ef->x509_der = eet_identity_check(ef->data,
1115 signature_base_offset,
1119 ef->data_size - signature_base_offset,
1121 &ef->signature_length,
1124 if (eet_test_close(ef->x509_der == NULL, ef))
1127 #else /* ifdef HAVE_SIGNATURE */
1129 "This file could be signed but you didn't compile the necessary code to check the signature.");
1130 #endif /* ifdef HAVE_SIGNATURE */
1134 } /* eet_internal_read2 */
1136 #if EET_OLD_EET_FILE_FORMAT
1138 eet_internal_read1(Eet_File *ef)
1140 const unsigned char *dyn_buf = NULL;
1141 const unsigned char *p = NULL;
1148 "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.",
1151 /* build header table if read mode */
1154 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1157 #define EXTRACT_INT(Value, Pointer, Index)\
1160 memcpy(&tmp, Pointer + Index, sizeof(int));\
1161 Value = ntohl(tmp);\
1162 Index += sizeof(int);\
1165 /* get entries count and byte count */
1166 EXTRACT_INT(num_entries, ef->data, idx);
1167 EXTRACT_INT(byte_entries, ef->data, idx);
1169 /* we cant have <= 0 values here - invalid */
1170 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1173 /* we can't have more entires than minimum bytes for those! invalid! */
1174 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1177 /* check we will not outrun the file limit */
1178 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1182 /* allocate header */
1183 ef->header = calloc(1, sizeof(Eet_File_Header));
1184 if (eet_test_close(!ef->header, ef))
1187 ef->header->magic = EET_MAGIC_FILE_HEADER;
1189 /* allocate directory block in ram */
1190 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1191 if (eet_test_close(!ef->header->directory, ef))
1194 /* 8 bit hash table (256 buckets) */
1195 ef->header->directory->size = 8;
1196 /* allocate base hash table */
1197 ef->header->directory->nodes =
1198 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1199 if (eet_test_close(!ef->header->directory->nodes, ef))
1202 /* actually read the directory block - all of it, into ram */
1203 dyn_buf = ef->data + idx;
1205 /* parse directory block */
1208 for (i = 0; i < num_entries; i++)
1217 #define HEADER_SIZE (sizeof(int) * 5)
1219 /* out directory block is inconsistent - we have oveerun our */
1220 /* dynamic block buffer before we finished scanning dir entries */
1221 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1224 /* allocate all the ram needed for this stored node accounting */
1225 efn = malloc (sizeof(Eet_File_Node));
1226 if (eet_test_close(!efn, ef))
1229 /* get entrie header */
1230 EXTRACT_INT(efn->offset, p, indexn);
1231 EXTRACT_INT(efn->compression, p, indexn);
1232 EXTRACT_INT(efn->size, p, indexn);
1233 EXTRACT_INT(efn->data_size, p, indexn);
1234 EXTRACT_INT(name_size, p, indexn);
1236 efn->name_size = name_size;
1241 if (eet_test_close(efn->size <= 0, ef))
1247 /* invalid name_size */
1248 if (eet_test_close(name_size <= 0, ef))
1254 /* reading name would mean falling off end of dyn_buf - invalid */
1255 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1261 /* This code is useless if we dont want backward compatibility */
1263 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1266 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1270 efn->name = malloc(sizeof(char) * name_size + 1);
1271 if (eet_test_close(efn->name == NULL, ef))
1277 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1278 efn->name[name_size] = 0;
1281 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1286 /* The only really usefull peace of code for efn->name (no backward compatibility) */
1287 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1289 /* get hash bucket it should go in */
1290 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1291 efn->next = ef->header->directory->nodes[hash];
1292 ef->header->directory->nodes[hash] = efn;
1294 /* read-only mode, so currently we have no data loaded */
1295 if (ef->mode == EET_FILE_MODE_READ)
1296 efn->data = NULL; /* read-write mode - read everything into ram */
1299 data = malloc(efn->size);
1301 memcpy(data, ef->data + efn->offset, efn->size);
1307 p += HEADER_SIZE + name_size;
1310 } /* eet_internal_read1 */
1312 #endif /* if EET_OLD_EET_FILE_FORMAT */
1315 * this should only be called when the cache lock is already held
1316 * (We could drop this restriction if we add a parameter to eet_test_close
1317 * that indicates if the lock is held or not. For now it is easiest
1318 * to just require that it is always held.)
1321 eet_internal_read(Eet_File *ef)
1323 const int *data = (const int *)ef->data;
1325 if (eet_test_close((ef->data == (void *)-1) || (ef->data == NULL), ef))
1328 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1331 switch (ntohl(*data))
1333 #if EET_OLD_EET_FILE_FORMAT
1334 case EET_MAGIC_FILE:
1335 return eet_internal_read1(ef);
1337 #endif /* if EET_OLD_EET_FILE_FORMAT */
1338 case EET_MAGIC_FILE2:
1339 return eet_internal_read2(ef);
1342 ef->delete_me_now = 1;
1343 eet_internal_close(ef, EINA_TRUE);
1348 } /* eet_internal_read */
1351 eet_internal_close(Eet_File *ef,
1356 /* check to see its' an eet file pointer */
1357 if (eet_check_pointer(ef))
1358 return EET_ERROR_BAD_OBJECT;
1365 /* if its still referenced - dont go any further */
1366 if (ef->references > 0)
1367 goto on_error; /* flush any writes */
1369 err = eet_flush2(ef);
1371 eet_identity_unref(ef->key);
1374 /* if not urgent to delete it - dont free it - leave it in cache */
1375 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1378 /* remove from cache */
1379 if (ef->mode == EET_FILE_MODE_READ)
1380 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1381 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1385 mode == EET_FILE_MODE_READ_WRITE))
1386 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1388 /* we can unlock the cache now */
1397 if (ef->header->directory)
1399 if (ef->header->directory->nodes)
1403 num = (1 << ef->header->directory->size);
1404 for (i = 0; i < num; i++)
1408 while ((efn = ef->header->directory->nodes[i]))
1413 ef->header->directory->nodes[i] = efn->next;
1421 free(ef->header->directory->nodes);
1424 free(ef->header->directory);
1430 eet_dictionary_free(ef->ed);
1436 munmap((void *)ef->data, ef->data_size);
1441 /* zero out ram for struct - caution tactic against stale memory use */
1442 memset(ef, 0, sizeof(Eet_File));
1452 return EET_ERROR_NONE;
1453 } /* eet_internal_close */
1456 eet_memopen_read(const void *data,
1461 if (data == NULL || size == 0)
1464 ef = malloc (sizeof (Eet_File));
1472 ef->magic = EET_MAGIC_FILE;
1474 ef->mode = EET_FILE_MODE_READ;
1477 ef->delete_me_now = 1;
1480 ef->data_size = size;
1482 ef->sha1_length = 0;
1484 /* eet_internal_read expects the cache lock to be held when it is called */
1486 ef = eet_internal_read(ef);
1489 } /* eet_memopen_read */
1492 eet_open(const char * file,
1498 struct stat file_stat;
1503 /* find the current file handle in cache*/
1506 if (mode == EET_FILE_MODE_READ)
1508 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1513 ef->delete_me_now = 1;
1514 eet_internal_close(ef, EINA_TRUE);
1517 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1519 else if ((mode == EET_FILE_MODE_WRITE) ||
1520 (mode == EET_FILE_MODE_READ_WRITE))
1522 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1525 ef->delete_me_now = 1;
1527 eet_internal_close(ef, EINA_TRUE);
1530 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1533 /* try open the file based on mode */
1534 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1536 /* Prevent garbage in futur comparison. */
1537 file_stat.st_mtime = 0;
1539 fp = fopen(file, "rb");
1543 if (fstat(fileno(fp), &file_stat))
1550 if ((mode == EET_FILE_MODE_READ) &&
1551 (file_stat.st_size < ((int)sizeof(int) * 3)))
1559 if (fp == NULL && mode == EET_FILE_MODE_READ)
1564 if (mode != EET_FILE_MODE_WRITE)
1567 memset(&file_stat, 0, sizeof(file_stat));
1574 ((file_stat.st_mtime != ef->mtime) ||
1575 (file_stat.st_size != ef->data_size)))
1577 ef->delete_me_now = 1;
1579 eet_internal_close(ef, EINA_TRUE);
1585 /* reference it up and return it */
1594 file_len = strlen(file) + 1;
1596 /* Allocate struct for eet file and have it zero'd out */
1597 ef = malloc(sizeof(Eet_File) + file_len);
1601 /* fill some of the members */
1605 ef->path = ((char *)ef) + sizeof(Eet_File);
1606 memcpy(ef->path, file, file_len);
1607 ef->magic = EET_MAGIC_FILE;
1611 ef->mtime = file_stat.st_mtime;
1612 ef->writes_pending = 0;
1613 ef->delete_me_now = 0;
1617 ef->sha1_length = 0;
1619 ef->ed = (mode == EET_FILE_MODE_WRITE)
1620 || (ef->readfp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
1621 eet_dictionary_add() : NULL;
1623 if (ef->readfp == NULL &&
1624 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1627 /* if we can't open - bail out */
1628 if (eet_test_close(!ef->readfp, ef))
1631 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1632 /* if we opened for read or read-write */
1633 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1635 ef->data_size = file_stat.st_size;
1636 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1637 MAP_SHARED, fileno(ef->readfp), 0);
1638 if (eet_test_close((ef->data == MAP_FAILED), ef))
1641 ef = eet_internal_read(ef);
1648 if (ef->references == 1)
1650 if (ef->mode == EET_FILE_MODE_READ)
1651 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1653 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1654 (ef->mode == EET_FILE_MODE_READ_WRITE))
1655 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1667 eet_mode_get(Eet_File *ef)
1669 /* check to see its' an eet file pointer */
1670 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1671 return EET_FILE_MODE_INVALID;
1674 } /* eet_mode_get */
1677 eet_identity_x509(Eet_File *ef,
1684 *der_length = ef->x509_length;
1686 return ef->x509_der;
1687 } /* eet_identity_x509 */
1690 eet_identity_signature(Eet_File *ef,
1691 int * signature_length)
1696 if (signature_length)
1697 *signature_length = ef->signature_length;
1699 return ef->signature;
1700 } /* eet_identity_signature */
1703 eet_identity_sha1(Eet_File *ef,
1707 ef->sha1 = eet_identity_compute_sha1(ef->data,
1712 *sha1_length = ef->sha1_length;
1715 } /* eet_identity_sha1 */
1718 eet_identity_set(Eet_File *ef,
1721 Eet_Key *tmp = ef->key;
1724 return EET_ERROR_BAD_OBJECT;
1727 eet_identity_ref(ef->key);
1728 eet_identity_unref(tmp);
1730 /* flags that writes are pending */
1731 ef->writes_pending = 1;
1733 return EET_ERROR_NONE;
1734 } /* eet_identity_set */
1737 eet_close(Eet_File *ef)
1739 return eet_internal_close(ef, EINA_FALSE);
1743 eet_read_cipher(Eet_File * ef,
1746 const char *cipher_key)
1755 /* check to see its' an eet file pointer */
1756 if (eet_check_pointer(ef))
1762 if ((ef->mode != EET_FILE_MODE_READ) &&
1763 (ef->mode != EET_FILE_MODE_READ_WRITE))
1766 /* no header, return NULL */
1767 if (eet_check_header(ef))
1772 /* hunt hash bucket */
1773 efn = find_node_by_name(ef, name);
1777 /* get size (uncompressed, if compressed at all) */
1778 size = efn->data_size;
1781 data = malloc(size);
1785 /* uncompressed data */
1786 if (efn->compression == 0)
1788 void *data_deciphered = NULL;
1789 unsigned int data_deciphered_sz = 0;
1790 /* if we alreayd have the data in ram... copy that */
1793 memcpy(data, efn->data, efn->size);
1795 if (!read_data_from_disk(ef, efn, data, size))
1798 if (efn->ciphered && cipher_key)
1800 if (eet_decipher(data, size, cipher_key, strlen(cipher_key),
1801 &data_deciphered, &data_deciphered_sz))
1803 if (data_deciphered)
1804 free(data_deciphered);
1810 data = data_deciphered;
1811 size = data_deciphered_sz;
1814 /* compressed data */
1818 void *data_deciphered = NULL;
1819 unsigned int data_deciphered_sz = 0;
1821 int compr_size = efn->size;
1824 /* if we already have the data in ram... copy that */
1826 tmp_data = efn->data;
1829 tmp_data = malloc(compr_size);
1835 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1842 if (efn->ciphered && cipher_key)
1844 if (eet_decipher(tmp_data, compr_size, cipher_key,
1845 strlen(cipher_key), &data_deciphered,
1846 &data_deciphered_sz))
1851 if (data_deciphered)
1852 free(data_deciphered);
1858 tmp_data = data_deciphered;
1859 compr_size = data_deciphered_sz;
1864 if (uncompress((Bytef *)data, &dlen,
1865 tmp_data, (uLongf)compr_size))
1879 if (data[size - 1] != '\0')
1882 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1889 /* fill in return values */
1899 } /* eet_read_cipher */
1902 eet_read(Eet_File * ef,
1906 return eet_read_cipher(ef, name, size_ret, NULL);
1910 eet_read_direct(Eet_File * ef,
1915 const char *data = NULL;
1921 /* check to see its' an eet file pointer */
1922 if (eet_check_pointer(ef))
1928 if ((ef->mode != EET_FILE_MODE_READ) &&
1929 (ef->mode != EET_FILE_MODE_READ_WRITE))
1932 /* no header, return NULL */
1933 if (eet_check_header(ef))
1938 /* hunt hash bucket */
1939 efn = find_node_by_name(ef, name);
1943 if (efn->offset < 0 && efn->data == NULL)
1946 /* get size (uncompressed, if compressed at all) */
1947 size = efn->data_size;
1951 data = efn->data ? efn->data : ef->data + efn->offset;
1953 /* handle alias case */
1954 if (efn->compression)
1957 int compr_size = efn->size;
1960 tmp = alloca(sizeof (compr_size));
1963 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1964 (uLongf)compr_size))
1967 if (tmp[compr_size - 1] != '\0')
1970 return eet_read_direct(ef, tmp, size_ret);
1976 if (data[size - 1] != '\0')
1979 return eet_read_direct(ef, data, size_ret);
1982 /* uncompressed data */
1983 if (efn->compression == 0
1984 && efn->ciphered == 0)
1985 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1989 /* fill in return values */
2000 } /* eet_read_direct */
2003 eet_alias(Eet_File * ef,
2005 const char *destination,
2010 Eina_Bool exists_already = EINA_FALSE;
2014 /* check to see its' an eet file pointer */
2015 if (eet_check_pointer(ef))
2018 if ((!name) || (!destination))
2021 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2022 (ef->mode != EET_FILE_MODE_READ_WRITE))
2029 /* allocate header */
2030 ef->header = calloc(1, sizeof(Eet_File_Header));
2034 ef->header->magic = EET_MAGIC_FILE_HEADER;
2035 /* allocate directory block in ram */
2036 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2037 if (!ef->header->directory)
2044 /* 8 bit hash table (256 buckets) */
2045 ef->header->directory->size = 8;
2046 /* allocate base hash table */
2047 ef->header->directory->nodes =
2048 calloc(1, sizeof(Eet_File_Node *) *
2049 (1 << ef->header->directory->size));
2050 if (!ef->header->directory->nodes)
2052 free(ef->header->directory);
2058 /* figure hash bucket */
2059 hash = _eet_hash_gen(name, ef->header->directory->size);
2062 12 + (((strlen(destination) + 1) * 101) / 100)
2063 : strlen(destination) + 1;
2065 data2 = malloc(data_size);
2069 /* if we want to compress */
2074 /* compress the data with max compression */
2075 buflen = (uLongf)data_size;
2076 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2077 (uLong)strlen(destination) + 1,
2078 Z_BEST_COMPRESSION) != Z_OK)
2084 /* record compressed chunk size */
2085 data_size = (int)buflen;
2086 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2089 data_size = strlen(destination) + 1;
2095 data3 = realloc(data2, data_size);
2102 memcpy(data2, destination, data_size);
2104 /* Does this node already exist? */
2105 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2108 if ((efn->name) && (eet_string_match(efn->name, name)))
2113 efn->compression = !!comp;
2114 efn->size = data_size;
2115 efn->data_size = strlen(destination) + 1;
2118 exists_already = EINA_TRUE;
2122 if (!exists_already)
2124 efn = malloc(sizeof(Eet_File_Node));
2131 efn->name = strdup(name);
2132 efn->name_size = strlen(efn->name) + 1;
2135 efn->next = ef->header->directory->nodes[hash];
2136 ef->header->directory->nodes[hash] = efn;
2140 efn->compression = !!comp;
2141 efn->size = data_size;
2142 efn->data_size = strlen(destination) + 1;
2146 /* flags that writes are pending */
2147 ef->writes_pending = 1;
2158 eet_write_cipher(Eet_File * ef,
2163 const char *cipher_key)
2167 int exists_already = 0;
2171 /* check to see its' an eet file pointer */
2172 if (eet_check_pointer(ef))
2175 if ((!name) || (!data) || (size <= 0))
2178 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2179 (ef->mode != EET_FILE_MODE_READ_WRITE))
2186 /* allocate header */
2187 ef->header = calloc(1, sizeof(Eet_File_Header));
2191 ef->header->magic = EET_MAGIC_FILE_HEADER;
2192 /* allocate directory block in ram */
2193 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2194 if (!ef->header->directory)
2201 /* 8 bit hash table (256 buckets) */
2202 ef->header->directory->size = 8;
2203 /* allocate base hash table */
2204 ef->header->directory->nodes =
2205 calloc(1, sizeof(Eet_File_Node *) *
2206 (1 << ef->header->directory->size));
2207 if (!ef->header->directory->nodes)
2209 free(ef->header->directory);
2215 /* figure hash bucket */
2216 hash = _eet_hash_gen(name, ef->header->directory->size);
2218 data_size = comp ? 12 + ((size * 101) / 100) : size;
2220 if (comp || !cipher_key)
2222 data2 = malloc(data_size);
2227 /* if we want to compress */
2232 /* compress the data with max compression */
2233 buflen = (uLongf)data_size;
2234 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2235 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2241 /* record compressed chunk size */
2242 data_size = (int)buflen;
2243 if (data_size < 0 || data_size >= size)
2252 data3 = realloc(data2, data_size);
2260 void *data_ciphered = NULL;
2261 unsigned int data_ciphered_sz = 0;
2264 tmp = data2 ? data2 : data;
2265 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2266 &data_ciphered, &data_ciphered_sz))
2271 data2 = data_ciphered;
2272 data_size = data_ciphered_sz;
2273 size = (data_size > size) ? data_size : size;
2278 free(data_ciphered);
2285 memcpy(data2, data, size);
2287 /* Does this node already exist? */
2288 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2291 if ((efn->name) && (eet_string_match(efn->name, name)))
2295 efn->ciphered = cipher_key ? 1 : 0;
2296 efn->compression = !!comp;
2297 efn->size = data_size;
2298 efn->data_size = size;
2305 if (!exists_already)
2307 efn = malloc(sizeof(Eet_File_Node));
2314 efn->name = strdup(name);
2315 efn->name_size = strlen(efn->name) + 1;
2318 efn->next = ef->header->directory->nodes[hash];
2319 ef->header->directory->nodes[hash] = efn;
2322 efn->ciphered = cipher_key ? 1 : 0;
2323 efn->compression = !!comp;
2324 efn->size = data_size;
2325 efn->data_size = size;
2329 /* flags that writes are pending */
2330 ef->writes_pending = 1;
2337 } /* eet_write_cipher */
2340 eet_write(Eet_File * ef,
2346 return eet_write_cipher(ef, name, data, size, comp, NULL);
2350 eet_delete(Eet_File * ef,
2354 Eet_File_Node *pefn;
2356 int exists_already = 0;
2358 /* check to see its' an eet file pointer */
2359 if (eet_check_pointer(ef))
2365 /* deleting keys is only possible in RW or WRITE mode */
2366 if (ef->mode == EET_FILE_MODE_READ)
2369 if (eet_check_header(ef))
2374 /* figure hash bucket */
2375 hash = _eet_hash_gen(name, ef->header->directory->size);
2377 /* Does this node already exist? */
2378 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2380 pefn = efn, efn = efn->next)
2383 if (eet_string_match(efn->name, name))
2389 ef->header->directory->nodes[hash] = efn->next;
2391 pefn->next = efn->next;
2401 /* flags that writes are pending */
2403 ef->writes_pending = 1;
2407 /* update access time */
2408 return exists_already;
2411 EAPI Eet_Dictionary *
2412 eet_dictionary_get(Eet_File *ef)
2414 if (eet_check_pointer(ef))
2418 } /* eet_dictionary_get */
2421 eet_list(Eet_File * ef,
2426 char **list_ret = NULL;
2428 int list_count_alloc = 0;
2431 /* check to see its' an eet file pointer */
2432 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2434 ((ef->mode != EET_FILE_MODE_READ) &&
2435 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2443 if (!strcmp(glob, "*"))
2448 /* loop through all entries */
2449 num = (1 << ef->header->directory->size);
2450 for (i = 0; i < num; i++)
2452 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2454 /* if the entry matches the input glob
2455 * check for * explicitly, because on some systems, * isn't well
2458 if ((!glob) || !fnmatch(glob, efn->name, 0))
2460 /* add it to our list */
2463 /* only realloc in 32 entry chunks */
2464 if (list_count > list_count_alloc)
2466 char **new_list = NULL;
2468 list_count_alloc += 64;
2470 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2478 list_ret = new_list;
2481 /* put pointer of name string in */
2482 list_ret[list_count - 1] = efn->name;
2489 /* return count and list */
2491 *count_ret = list_count;
2505 eet_num_entries(Eet_File *ef)
2507 int i, num, ret = 0;
2510 /* check to see its' an eet file pointer */
2511 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2512 ((ef->mode != EET_FILE_MODE_READ) &&
2513 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2518 /* loop through all entries */
2519 num = (1 << ef->header->directory->size);
2520 for (i = 0; i < num; i++)
2522 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2529 } /* eet_num_entries */
2531 static Eet_File_Node *
2532 find_node_by_name(Eet_File * ef,
2538 /* get hash bucket this should be in */
2539 hash = _eet_hash_gen(name, ef->header->directory->size);
2541 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2543 if (eet_string_match(efn->name, name))
2548 } /* find_node_by_name */
2551 read_data_from_disk(Eet_File * ef,
2556 if (efn->offset < 0)
2561 if ((efn->offset + len) > ef->data_size)
2564 memcpy(buf, ef->data + efn->offset, len);
2571 /* seek to data location */
2572 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2576 len = fread(buf, len, 1, ef->readfp);
2580 } /* read_data_from_disk */