2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
11 #elif defined __GNUC__
12 # define alloca __builtin_alloca
14 # define alloca __alloca
15 #elif defined _MSC_VER
17 # define alloca _alloca
23 void *alloca (size_t);
27 # include <winsock2.h>
32 #include <sys/types.h>
45 #ifdef HAVE_NETINET_IN_H
46 # include <netinet/in.h>
54 # include <gnutls/gnutls.h>
59 # include <openssl/err.h>
60 # include <openssl/evp.h>
63 #ifdef EFL_HAVE_PTHREAD
70 #include "Eet_private.h"
72 static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
73 EAPI Eet_Version *eet_version = &_version;
79 #define EET_MAGIC_FILE 0x1ee7ff00
80 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
82 #define EET_MAGIC_FILE2 0x1ee70f42
84 typedef struct _Eet_File_Header Eet_File_Header;
85 typedef struct _Eet_File_Node Eet_File_Node;
86 typedef struct _Eet_File_Directory Eet_File_Directory;
92 Eet_File_Header *header;
95 const unsigned char *data;
97 const void *signature;
107 unsigned int signature_length;
112 #ifdef EFL_HAVE_PTHREAD
113 pthread_mutex_t file_lock;
116 unsigned char writes_pending : 1;
117 unsigned char delete_me_now : 1;
120 struct _Eet_File_Header
123 Eet_File_Directory *directory;
126 struct _Eet_File_Directory
129 Eet_File_Node **nodes;
132 struct _Eet_File_Node
136 Eet_File_Node *next; /* FIXME: make buckets linked lists */
139 int dictionary_offset;
146 unsigned char free_name : 1;
147 unsigned char compression : 1;
148 unsigned char ciphered : 1;
149 unsigned char alias : 1;
154 /* NB: all int's are stored in network byte order on disk */
156 int magic; /* magic number ie 0x1ee7ff00 */
157 int num_directory_entries; /* number of directory entries to follow */
158 int bytes_directory_entries; /* bytes of directory entries to follow */
161 int offset; /* bytes offset into file for data chunk */
162 int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
163 int size; /* size of the data chunk */
164 int data_size; /* size of the (uncompressed) data chunk */
165 int name_size; /* length in bytes of the name field */
166 char name[name_size]; /* name string (variable length) and \0 terminated */
167 } directory[num_directory_entries];
168 /* and now startes the data stream... */
173 /* NB: all int's are stored in network byte order on disk */
175 int magic; /* magic number ie 0x1ee70f42 */
176 int num_directory_entries; /* number of directory entries to follow */
177 int num_dictionary_entries; /* number of dictionary entries to follow */
180 int data_offset; /* bytes offset into file for data chunk */
181 int size; /* size of the data chunk */
182 int data_size; /* size of the (uncompressed) data chunk */
183 int name_offset; /* bytes offset into file for name string */
184 int name_size; /* length in bytes of the name field */
185 int flags; /* bit flags - for now:
186 bit 0 => compresion on/off
187 bit 1 => ciphered on/off
190 } directory[num_directory_entries];
198 } dictionary[num_dictionary_entries];
199 /* now start the string stream. */
200 /* and right after them the data stream. */
201 int magic_sign; /* Optional, only if the eet file is signed. */
202 int signature_length; /* Signature length. */
203 int x509_length; /* Public certificate that signed the file. */
204 char signature[signature_length]; /* The signature. */
205 char x509[x509_length]; /* The public certificate. */
208 #define EET_FILE2_HEADER_COUNT 3
209 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
210 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
212 #define EET_FILE2_HEADER_SIZE (sizeof(int) * EET_FILE2_HEADER_COUNT)
213 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DIRECTORY_ENTRY_COUNT)
214 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DICTIONARY_ENTRY_COUNT)
216 /* prototypes of internal calls */
217 static Eet_File *eet_cache_find(const char *path, Eet_File **cache, int cache_num);
218 static void eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
219 static void eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
220 static int eet_string_match(const char *s1, const char *s2);
222 static Eet_Error eet_flush(Eet_File *ef);
224 static Eet_Error eet_flush2(Eet_File *ef);
225 static Eet_File_Node *find_node_by_name(Eet_File *ef, const char *name);
226 static int read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len);
228 static Eet_Error eet_internal_close(Eet_File *ef, Eina_Bool locked);
230 #ifdef EFL_HAVE_PTHREAD
231 static pthread_mutex_t eet_cache_lock = PTHREAD_MUTEX_INITIALIZER;
233 #define LOCK_CACHE pthread_mutex_lock(&eet_cache_lock);
234 #define UNLOCK_CACHE pthread_mutex_unlock(&eet_cache_lock);
236 #define INIT_FILE(File) pthread_mutex_init(&File->file_lock, NULL);
237 #define LOCK_FILE(File) pthread_mutex_lock(&File->file_lock);
238 #define UNLOCK_FILE(File) pthread_mutex_unlock(&File->file_lock);
239 #define DESTROY_FILE(File) pthread_mutex_destroy(&File->file_lock);
244 #define UNLOCK_CACHE ;
246 #define INIT_FILE(File) ;
247 #define LOCK_FILE(File) ;
248 #define UNLOCK_FILE(File) ;
249 #define DESTROY_FILE(File) ;
253 /* cache. i don't expect this to ever be large, so arrays will do */
254 static int eet_writers_num = 0;
255 static int eet_writers_alloc = 0;
256 static Eet_File **eet_writers = NULL;
257 static int eet_readers_num = 0;
258 static int eet_readers_alloc = 0;
259 static Eet_File **eet_readers = NULL;
260 static int eet_init_count = 0;
262 /* log domain variable */
263 int _eet_log_dom_global = -1;
265 /* Check to see its' an eet file pointer */
267 eet_check_pointer(const Eet_File *ef)
269 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
275 eet_check_header(const Eet_File *ef)
279 if (!ef->header->directory)
285 eet_test_close(int test, Eet_File *ef)
289 ef->delete_me_now = 1;
290 eet_internal_close(ef, EINA_TRUE);
295 /* find an eet file in the currently in use cache */
297 eet_cache_find(const char *path, Eet_File **cache, int cache_num)
302 for (i = 0; i < cache_num; i++)
304 /* if matches real path - return it */
305 if (eet_string_match(cache[i]->path, path))
307 if (!cache[i]->delete_me_now)
316 /* add to end of cache */
317 /* this should only be called when the cache lock is already held */
319 eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
321 Eet_File **new_cache;
325 new_cache_num = *cache_num;
326 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
328 Eet_File *del_ef = NULL;
332 for (i = 0; i < new_cache_num; i++)
334 if (new_cache[i]->references == 0)
336 del_ef = new_cache[i];
343 del_ef->delete_me_now = 1;
344 eet_internal_close(del_ef, EINA_TRUE);
349 new_cache_num = *cache_num;
350 new_cache_alloc = *cache_alloc;
352 if (new_cache_num > new_cache_alloc)
354 new_cache_alloc += 16;
355 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
358 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
362 new_cache[new_cache_num - 1] = ef;
364 *cache_num = new_cache_num;
365 *cache_alloc = new_cache_alloc;
368 /* delete from cache */
369 /* this should only be called when the cache lock is already held */
371 eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
373 Eet_File **new_cache;
374 int new_cache_num, new_cache_alloc;
378 new_cache_num = *cache_num;
379 new_cache_alloc = *cache_alloc;
380 if (new_cache_num <= 0)
383 for (i = 0; i < new_cache_num; i++)
385 if (new_cache[i] == ef)
389 if (i >= new_cache_num)
393 for (j = i; j < new_cache_num; j++)
394 new_cache[j] = new_cache[j + 1];
396 if (new_cache_num <= (new_cache_alloc - 16))
398 new_cache_alloc -= 16;
399 if (new_cache_num > 0)
401 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
404 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
415 *cache_num = new_cache_num;
416 *cache_alloc = new_cache_alloc;
419 /* internal string match. null friendly, catches same ptr */
421 eet_string_match(const char *s1, const char *s2)
423 /* both null- no match */
424 if ((!s1) || (!s2)) return 0;
425 if (s1 == s2) return 1;
426 return (!strcmp(s1, s2));
429 /* flush out writes to a v2 eet file */
431 eet_flush2(Eet_File *ef)
435 Eet_Error error = EET_ERROR_NONE;
436 int head[EET_FILE2_HEADER_COUNT];
437 int num_directory_entries = 0;
438 int num_dictionary_entries = 0;
439 int bytes_directory_entries = 0;
440 int bytes_dictionary_entries = 0;
441 int bytes_strings = 0;
443 int strings_offset = 0;
448 if (eet_check_pointer(ef))
449 return EET_ERROR_BAD_OBJECT;
450 if (eet_check_header(ef))
451 return EET_ERROR_EMPTY;
452 if (!ef->writes_pending)
453 return EET_ERROR_NONE;
455 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
456 || (ef->mode == EET_FILE_MODE_WRITE))
460 /* opening for write - delete old copy of file right away */
462 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
463 fp = fdopen(fd, "wb");
464 if (!fp) return EET_ERROR_NOT_WRITABLE;
465 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
468 return EET_ERROR_NOT_WRITABLE;
470 /* calculate string base offset and data base offset */
471 num = (1 << ef->header->directory->size);
472 for (i = 0; i < num; ++i)
474 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
476 num_directory_entries++;
477 bytes_strings += strlen(efn->name) + 1;
482 num_dictionary_entries = ef->ed->count;
484 for (i = 0; i < num_dictionary_entries; ++i)
485 bytes_strings += ef->ed->all[i].len;
488 /* calculate section bytes size */
489 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
490 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
492 /* calculate per entry offset */
493 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
494 data_offset = bytes_directory_entries + bytes_dictionary_entries + bytes_strings;
496 for (i = 0; i < num; ++i)
498 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
500 efn->offset = data_offset;
501 data_offset += efn->size;
503 efn->name_offset = strings_offset;
504 strings_offset += efn->name_size;
508 /* calculate dictionary strings offset */
510 ef->ed->offset = strings_offset;
512 /* go thru and write the header */
513 head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE2);
514 head[1] = (int) htonl ((unsigned int) num_directory_entries);
515 head[2] = (int) htonl ((unsigned int) num_dictionary_entries);
517 fseek(fp, 0, SEEK_SET);
518 if (fwrite(head, sizeof (head), 1, fp) != 1)
521 /* write directories entry */
522 for (i = 0; i < num; i++)
524 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
527 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
529 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
531 ibuf[0] = (int) htonl ((unsigned int) efn->offset);
532 ibuf[1] = (int) htonl ((unsigned int) efn->size);
533 ibuf[2] = (int) htonl ((unsigned int) efn->data_size);
534 ibuf[3] = (int) htonl ((unsigned int) efn->name_offset);
535 ibuf[4] = (int) htonl ((unsigned int) efn->name_size);
536 ibuf[5] = (int) htonl ((unsigned int) flag);
538 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
543 /* write dictionnary */
546 int offset = strings_offset;
548 for (j = 0; j < ef->ed->count; ++j)
550 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
552 sbuf[0] = (int) htonl ((unsigned int) ef->ed->all[j].hash);
553 sbuf[1] = (int) htonl ((unsigned int) offset);
554 sbuf[2] = (int) htonl ((unsigned int) ef->ed->all[j].len);
555 sbuf[3] = (int) htonl ((unsigned int) ef->ed->all[j].prev);
556 sbuf[4] = (int) htonl ((unsigned int) ef->ed->all[j].next);
558 offset += ef->ed->all[j].len;
560 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
565 /* write directories name */
566 for (i = 0; i < num; i++)
568 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
570 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
578 for (j = 0; j < ef->ed->count; ++j)
580 if (ef->ed->all[j].str)
582 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
587 if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, fp) != 1)
594 for (i = 0; i < num; i++)
596 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
598 if (fwrite(efn->data, efn->size, 1, fp) != 1)
603 /* flush all write to the file. */
605 // this is going to really cause trouble. if ANYTHING this needs to go into a
606 // thread spawned off - but even then...
607 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
608 // manual pages at eachother, but ext4 broke behavior that has been in place
609 // for decades and that 1000's of apps rely on daily - that is that one operation
610 // to disk is committed to disk BEFORE following operations, so the fs retains
611 // a consistent state
612 // fsync(fileno(fp));
614 /* append signature if required */
617 error = eet_identity_sign(fp, ef->key);
618 if (error != EET_ERROR_NONE)
622 /* no more writes pending */
623 ef->writes_pending = 0;
627 return EET_ERROR_NONE;
634 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
635 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
636 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
637 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
638 default: error = EET_ERROR_WRITE_ERROR; break;
649 if (++eet_init_count != 1)
650 return eet_init_count;
654 fprintf(stderr, "Eet: Eina init failed");
655 return --eet_init_count;
657 _eet_log_dom_global = eina_log_domain_register("Eet", EET_DEFAULT_LOG_COLOR);
658 if (_eet_log_dom_global < 0)
660 EINA_LOG_ERR("Eet Can not create a general log domain.");
664 if (!eet_node_init())
666 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
667 goto unregister_log_domain;
671 /* Before the library can be used, it must initialize itself if needed. */
672 if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0)
674 gcry_check_version(NULL);
675 /* Disable warning messages about problems with the secure memory subsystem.
676 This command should be run right after gcry_check_version. */
677 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
679 /* This command is used to allocate a pool of secure memory and thus
680 enabling the use of secure memory. It also drops all extra privileges the
681 process has (i.e. if it is run as setuid (root)). If the argument nbytes
682 is 0, secure memory will be disabled. The minimum amount of secure memory
683 allocated is currently 16384 bytes; you may thus use a value of 1 to
684 request that default size. */
685 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
686 WRN("BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
688 if (gnutls_global_init())
692 ERR_load_crypto_strings();
693 OpenSSL_add_all_algorithms();
696 return eet_init_count;
700 unregister_log_domain:
701 eina_log_domain_unregister(_eet_log_dom_global);
702 _eet_log_dom_global = -1;
705 return --eet_init_count;
711 if (--eet_init_count != 0)
712 return eet_init_count;
717 gnutls_global_deinit();
723 eina_log_domain_unregister(_eet_log_dom_global);
724 _eet_log_dom_global = -1;
727 return eet_init_count;
731 eet_sync(Eet_File *ef)
735 if (eet_check_pointer(ef))
736 return EET_ERROR_BAD_OBJECT;
738 if ((ef->mode != EET_FILE_MODE_WRITE) &&
739 (ef->mode != EET_FILE_MODE_READ_WRITE))
740 return EET_ERROR_NOT_WRITABLE;
742 if (!ef->writes_pending)
743 return EET_ERROR_NONE;
747 ret = eet_flush2(ef);
760 * We need to compute the list of eet file to close separately from the cache,
761 * due to eet_close removing them from the cache after each call.
764 for (i = 0; i < eet_writers_num; i++)
766 if (eet_writers[i]->references <= 0) num++;
769 for (i = 0; i < eet_readers_num; i++)
771 if (eet_readers[i]->references <= 0) num++;
776 Eet_File **closelist = NULL;
778 closelist = alloca(num * sizeof(Eet_File *));
780 for (i = 0; i < eet_writers_num; i++)
782 if (eet_writers[i]->references <= 0)
784 closelist[num] = eet_writers[i];
785 eet_writers[i]->delete_me_now = 1;
790 for (i = 0; i < eet_readers_num; i++)
792 if (eet_readers[i]->references <= 0)
794 closelist[num] = eet_readers[i];
795 eet_readers[i]->delete_me_now = 1;
800 for (i = 0; i < num; i++)
802 eet_internal_close(closelist[i], EINA_TRUE);
808 /* FIXME: MMAP race condition in READ_WRITE_MODE */
810 eet_internal_read2(Eet_File *ef)
812 const int *data = (const int*) ef->data;
813 const char *start = (const char*) ef->data;
815 int num_directory_entries;
816 int bytes_directory_entries;
817 int num_dictionary_entries;
818 int bytes_dictionary_entries;
819 int signature_base_offset;
823 if (eet_test_close((int) ntohl(*data) != EET_MAGIC_FILE2, ef))
827 #define GET_INT(Value, Pointer, Index) \
829 Value = ntohl(*Pointer); \
831 Index += sizeof(int); \
834 /* get entries count and byte count */
835 GET_INT(num_directory_entries, data, idx);
836 /* get dictionary count and byte count */
837 GET_INT(num_dictionary_entries, data, idx);
839 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
840 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
842 /* we cant have <= 0 values here - invalid */
843 if (eet_test_close((num_directory_entries <= 0), ef))
846 /* we cant have more bytes directory and bytes in dictionaries than the size of the file */
847 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) > ef->data_size, ef))
850 /* allocate header */
851 ef->header = calloc(1, sizeof(Eet_File_Header));
852 if (eet_test_close(!ef->header, ef))
855 ef->header->magic = EET_MAGIC_FILE_HEADER;
857 /* allocate directory block in ram */
858 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
859 if (eet_test_close(!ef->header->directory, ef))
862 /* 8 bit hash table (256 buckets) */
863 ef->header->directory->size = 8;
864 /* allocate base hash table */
865 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
866 if (eet_test_close(!ef->header->directory->nodes, ef))
869 signature_base_offset = 0;
871 /* actually read the directory block - all of it, into ram */
872 for (i = 0; i < num_directory_entries; ++i)
881 /* out directory block is inconsistent - we have oveerun our */
882 /* dynamic block buffer before we finished scanning dir entries */
883 efn = malloc (sizeof(Eet_File_Node));
884 if (eet_test_close(!efn, ef))
887 /* get entrie header */
888 GET_INT(efn->offset, data, idx);
889 GET_INT(efn->size, data, idx);
890 GET_INT(efn->data_size, data, idx);
891 GET_INT(name_offset, data, idx);
892 GET_INT(name_size, data, idx);
893 GET_INT(flag, data, idx);
895 efn->compression = flag & 0x1 ? 1 : 0;
896 efn->ciphered = flag & 0x2 ? 1 : 0;
897 efn->alias = flag & 0x4 ? 1 : 0;
899 #define EFN_TEST(Test, Ef, Efn) \
900 if (eet_test_close(Test, Ef)) \
906 /* check data pointer position */
907 EFN_TEST(!((efn->size > 0)
908 && (efn->offset + efn->size <= ef->data_size)
909 && (efn->offset > bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
911 /* check name position */
912 EFN_TEST(!((name_size > 0)
913 && (name_offset + name_size < ef->data_size)
914 && (name_offset >= bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
916 name = start + name_offset;
918 /* check '\0' at the end of name string */
919 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
922 efn->name = (char*) name;
923 efn->name_size = name_size;
925 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
926 efn->next = ef->header->directory->nodes[hash];
927 ef->header->directory->nodes[hash] = efn;
929 /* read-only mode, so currently we have no data loaded */
930 if (ef->mode == EET_FILE_MODE_READ)
932 /* read-write mode - read everything into ram */
935 efn->data = malloc(efn->size);
937 memcpy(efn->data, ef->data + efn->offset, efn->size);
940 /* compute the possible position of a signature */
941 if (signature_base_offset < efn->offset + efn->size)
942 signature_base_offset = efn->offset + efn->size;
947 if (num_dictionary_entries)
949 const int *dico = (const int*) ef->data + EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries + EET_FILE2_HEADER_COUNT;
952 if (eet_test_close((num_dictionary_entries * (int) EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) > (bytes_dictionary_entries + bytes_directory_entries), ef))
955 ef->ed = calloc(1, sizeof (Eet_Dictionary));
956 if (eet_test_close(!ef->ed, ef)) return NULL;
958 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
959 if (eet_test_close(!ef->ed->all, ef)) return NULL;
961 ef->ed->count = num_dictionary_entries;
962 ef->ed->total = num_dictionary_entries;
963 ef->ed->start = start + bytes_dictionary_entries + bytes_directory_entries;
964 ef->ed->end = ef->ed->start;
966 for (j = 0; j < ef->ed->count; ++j)
971 GET_INT(hash, dico, idx);
972 GET_INT(offset, dico, idx);
973 GET_INT(ef->ed->all[j].len, dico, idx);
974 GET_INT(ef->ed->all[j].prev, dico, idx);
975 GET_INT(ef->ed->all[j].next, dico, idx);
977 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
978 So stick to int and check the value. */
979 if (eet_test_close(hash & 0xFFFFFF00, ef)) return NULL;
981 /* Check string position */
982 if (eet_test_close(!((ef->ed->all[j].len > 0)
983 && (offset > (bytes_dictionary_entries + bytes_directory_entries))
984 && (offset + ef->ed->all[j].len < ef->data_size)), ef))
987 ef->ed->all[j].mmap = start + offset;
988 ef->ed->all[j].str = NULL;
990 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
991 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
993 /* Check '\0' at the end of the string */
994 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] != '\0', ef)) return NULL;
996 ef->ed->all[j].hash = hash;
997 if (ef->ed->all[j].prev == -1)
998 ef->ed->hash[hash] = j;
1000 /* compute the possible position of a signature */
1001 if (signature_base_offset < offset + ef->ed->all[j].len)
1002 signature_base_offset = offset + ef->ed->all[j].len;
1006 /* Check if the file is signed */
1007 ef->x509_der = NULL;
1008 ef->x509_length = 0;
1009 ef->signature = NULL;
1010 ef->signature_length = 0;
1012 if (signature_base_offset < ef->data_size)
1014 #ifdef HAVE_SIGNATURE
1015 const unsigned char *buffer = ((const unsigned char*) ef->data) + signature_base_offset;
1016 ef->x509_der = eet_identity_check(ef->data, signature_base_offset,
1017 &ef->sha1, &ef->sha1_length,
1018 buffer, ef->data_size - signature_base_offset,
1019 &ef->signature, &ef->signature_length,
1022 if (eet_test_close(ef->x509_der == NULL, ef)) return NULL;
1024 ERR("This file could be signed but you didn't compile the necessary code to check the signature.");
1031 #if EET_OLD_EET_FILE_FORMAT
1033 eet_internal_read1(Eet_File *ef)
1035 const unsigned char *dyn_buf = NULL;
1036 const unsigned char *p = NULL;
1042 WRN("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.", ef->path);
1044 /* build header table if read mode */
1047 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1050 #define EXTRACT_INT(Value, Pointer, Index) \
1053 memcpy(&tmp, Pointer + Index, sizeof(int)); \
1054 Value = ntohl(tmp); \
1055 Index += sizeof(int); \
1058 /* get entries count and byte count */
1059 EXTRACT_INT(num_entries, ef->data, idx);
1060 EXTRACT_INT(byte_entries, ef->data, idx);
1062 /* we cant have <= 0 values here - invalid */
1063 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1066 /* we can't have more entires than minimum bytes for those! invalid! */
1067 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1070 /* check we will not outrun the file limit */
1071 if (eet_test_close(((byte_entries + (int) sizeof(int) * 3) > ef->data_size), ef))
1074 /* allocate header */
1075 ef->header = calloc(1, sizeof(Eet_File_Header));
1076 if (eet_test_close(!ef->header, ef))
1079 ef->header->magic = EET_MAGIC_FILE_HEADER;
1081 /* allocate directory block in ram */
1082 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1083 if (eet_test_close(!ef->header->directory, ef))
1086 /* 8 bit hash table (256 buckets) */
1087 ef->header->directory->size = 8;
1088 /* allocate base hash table */
1089 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1090 if (eet_test_close(!ef->header->directory->nodes, ef))
1093 /* actually read the directory block - all of it, into ram */
1094 dyn_buf = ef->data + idx;
1096 /* parse directory block */
1099 for (i = 0; i < num_entries; i++)
1108 #define HEADER_SIZE (sizeof(int) * 5)
1110 /* out directory block is inconsistent - we have oveerun our */
1111 /* dynamic block buffer before we finished scanning dir entries */
1112 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1115 /* allocate all the ram needed for this stored node accounting */
1116 efn = malloc (sizeof(Eet_File_Node));
1117 if (eet_test_close(!efn, ef))
1120 /* get entrie header */
1121 EXTRACT_INT(efn->offset, p, indexn);
1122 EXTRACT_INT(efn->compression, p, indexn);
1123 EXTRACT_INT(efn->size, p, indexn);
1124 EXTRACT_INT(efn->data_size, p, indexn);
1125 EXTRACT_INT(name_size, p, indexn);
1127 efn->name_size = name_size;
1132 if (eet_test_close(efn->size <= 0, ef))
1138 /* invalid name_size */
1139 if (eet_test_close(name_size <= 0, ef))
1145 /* reading name would mean falling off end of dyn_buf - invalid */
1146 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1152 /* This code is useless if we dont want backward compatibility */
1153 for (k = name_size; k > 0 && ((unsigned char) * (p + HEADER_SIZE + k)) != 0; --k)
1156 efn->free_name = ((unsigned char) * (p + HEADER_SIZE + k)) != 0;
1160 efn->name = malloc(sizeof(char) * name_size + 1);
1161 if (eet_test_close(efn->name == NULL, ef))
1167 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1168 efn->name[name_size] = 0;
1170 WRN("File: %s is not up to date for key \"%s\" - needs rebuilding sometime", ef->path, efn->name);
1173 /* The only really usefull peace of code for efn->name (no backward compatibility) */
1174 efn->name = (char*)((unsigned char*)(p + HEADER_SIZE));
1176 /* get hash bucket it should go in */
1177 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1178 efn->next = ef->header->directory->nodes[hash];
1179 ef->header->directory->nodes[hash] = efn;
1181 /* read-only mode, so currently we have no data loaded */
1182 if (ef->mode == EET_FILE_MODE_READ)
1184 /* read-write mode - read everything into ram */
1187 data = malloc(efn->size);
1189 memcpy(data, ef->data + efn->offset, efn->size);
1193 p += HEADER_SIZE + name_size;
1200 * this should only be called when the cache lock is already held
1201 * (We could drop this restriction if we add a parameter to eet_test_close
1202 * that indicates if the lock is held or not. For now it is easiest
1203 * to just require that it is always held.)
1206 eet_internal_read(Eet_File *ef)
1208 const int *data = (const int*) ef->data;
1210 if (eet_test_close((ef->data == (void *)-1) || (ef->data == NULL), ef))
1213 if (eet_test_close(ef->data_size < (int) sizeof(int) * 3, ef))
1216 switch (ntohl(*data))
1218 #if EET_OLD_EET_FILE_FORMAT
1219 case EET_MAGIC_FILE:
1220 return eet_internal_read1(ef);
1222 case EET_MAGIC_FILE2:
1223 return eet_internal_read2(ef);
1225 ef->delete_me_now = 1;
1226 eet_internal_close(ef, EINA_TRUE);
1234 eet_internal_close(Eet_File *ef, Eina_Bool locked)
1238 /* check to see its' an eet file pointer */
1239 if (eet_check_pointer(ef))
1240 return EET_ERROR_BAD_OBJECT;
1242 if (!locked) LOCK_CACHE;
1246 /* if its still referenced - dont go any further */
1247 if (ef->references > 0) goto on_error;
1248 /* flush any writes */
1249 err = eet_flush2(ef);
1251 eet_identity_unref(ef->key);
1254 /* if not urgent to delete it - dont free it - leave it in cache */
1255 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1258 /* remove from cache */
1259 if (ef->mode == EET_FILE_MODE_READ)
1260 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1261 else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1262 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1264 /* we can unlock the cache now */
1265 if (!locked) UNLOCK_CACHE;
1272 if (ef->header->directory)
1274 if (ef->header->directory->nodes)
1278 num = (1 << ef->header->directory->size);
1279 for (i = 0; i < num; i++)
1283 while ((efn = ef->header->directory->nodes[i]))
1288 ef->header->directory->nodes[i] = efn->next;
1296 free(ef->header->directory->nodes);
1298 free(ef->header->directory);
1303 eet_dictionary_free(ef->ed);
1305 if (ef->sha1) free(ef->sha1);
1306 if (ef->data) munmap((void*)ef->data, ef->data_size);
1307 if (ef->readfp) fclose(ef->readfp);
1309 /* zero out ram for struct - caution tactic against stale memory use */
1310 memset(ef, 0, sizeof(Eet_File));
1317 if (!locked) UNLOCK_CACHE;
1318 return EET_ERROR_NONE;
1322 eet_memopen_read(const void *data, size_t size)
1326 if (data == NULL || size == 0)
1329 ef = malloc (sizeof (Eet_File));
1337 ef->magic = EET_MAGIC_FILE;
1339 ef->mode = EET_FILE_MODE_READ;
1342 ef->delete_me_now = 1;
1345 ef->data_size = size;
1347 ef->sha1_length = 0;
1349 /* eet_internal_read expects the cache lock to be held when it is called */
1351 ef = eet_internal_read(ef);
1357 eet_open(const char *file, Eet_File_Mode mode)
1362 struct stat file_stat;
1367 /* find the current file handle in cache*/
1370 if (mode == EET_FILE_MODE_READ)
1372 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1377 ef->delete_me_now = 1;
1378 eet_internal_close(ef, EINA_TRUE);
1380 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1382 else if ((mode == EET_FILE_MODE_WRITE) ||
1383 (mode == EET_FILE_MODE_READ_WRITE))
1385 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1388 ef->delete_me_now = 1;
1390 eet_internal_close(ef, EINA_TRUE);
1392 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1395 /* try open the file based on mode */
1396 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1398 /* Prevent garbage in futur comparison. */
1399 file_stat.st_mtime = 0;
1401 fp = fopen(file, "rb");
1402 if (!fp) goto open_error;
1403 if (fstat(fileno(fp), &file_stat))
1409 if ((mode == EET_FILE_MODE_READ) &&
1410 (file_stat.st_size < ((int) sizeof(int) * 3)))
1418 if (fp == NULL && mode == EET_FILE_MODE_READ) goto on_error;
1422 if (mode != EET_FILE_MODE_WRITE) return NULL;
1423 memset(&file_stat, 0, sizeof(file_stat));
1429 if (ef && (file_stat.st_mtime != ef->mtime))
1431 ef->delete_me_now = 1;
1433 eet_internal_close(ef, EINA_TRUE);
1439 /* reference it up and return it */
1440 if (fp != NULL) fclose(fp);
1446 file_len = strlen(file) + 1;
1448 /* Allocate struct for eet file and have it zero'd out */
1449 ef = malloc(sizeof(Eet_File) + file_len);
1453 /* fill some of the members */
1457 ef->path = ((char *)ef) + sizeof(Eet_File);
1458 memcpy(ef->path, file, file_len);
1459 ef->magic = EET_MAGIC_FILE;
1463 ef->mtime = file_stat.st_mtime;
1464 ef->writes_pending = 0;
1465 ef->delete_me_now = 0;
1469 ef->sha1_length = 0;
1471 ef->ed = (mode == EET_FILE_MODE_WRITE)
1472 || (ef->readfp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
1473 eet_dictionary_add() : NULL;
1475 if (ef->readfp == NULL &&
1476 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1479 /* if we can't open - bail out */
1480 if (eet_test_close(!ef->readfp, ef))
1483 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1484 /* if we opened for read or read-write */
1485 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1487 ef->data_size = file_stat.st_size;
1488 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1489 MAP_SHARED, fileno(ef->readfp), 0);
1490 if (eet_test_close((ef->data == MAP_FAILED), ef))
1492 ef = eet_internal_read(ef);
1499 if (ef->references == 1)
1501 if (ef->mode == EET_FILE_MODE_READ)
1502 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1504 if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1505 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1517 eet_mode_get(Eet_File *ef)
1519 /* check to see its' an eet file pointer */
1520 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1521 return EET_FILE_MODE_INVALID;
1527 eet_identity_x509(Eet_File *ef, int *der_length)
1529 if (!ef->x509_der) return NULL;
1531 if (der_length) *der_length = ef->x509_length;
1532 return ef->x509_der;
1536 eet_identity_signature(Eet_File *ef, int *signature_length)
1538 if (!ef->signature) return NULL;
1540 if (signature_length) *signature_length = ef->signature_length;
1541 return ef->signature;
1545 eet_identity_sha1(Eet_File *ef, int *sha1_length)
1548 ef->sha1 = eet_identity_compute_sha1(ef->data, ef->data_size, &ef->sha1_length);
1550 if (sha1_length) *sha1_length = ef->sha1_length;
1555 eet_identity_set(Eet_File *ef, Eet_Key *key)
1557 Eet_Key *tmp = ef->key;
1559 if (!ef) return EET_ERROR_BAD_OBJECT;
1562 eet_identity_ref(ef->key);
1563 eet_identity_unref(tmp);
1565 /* flags that writes are pending */
1566 ef->writes_pending = 1;
1568 return EET_ERROR_NONE;
1572 eet_close(Eet_File *ef)
1574 return eet_internal_close(ef, EINA_FALSE);
1578 eet_read_cipher(Eet_File *ef, const char *name, int *size_ret, const char *cipher_key)
1587 /* check to see its' an eet file pointer */
1588 if (eet_check_pointer(ef))
1592 if ((ef->mode != EET_FILE_MODE_READ) &&
1593 (ef->mode != EET_FILE_MODE_READ_WRITE))
1596 /* no header, return NULL */
1597 if (eet_check_header(ef))
1602 /* hunt hash bucket */
1603 efn = find_node_by_name(ef, name);
1604 if (!efn) goto on_error;
1606 /* get size (uncompressed, if compressed at all) */
1607 size = efn->data_size;
1610 data = malloc(size);
1611 if (!data) goto on_error;
1613 /* uncompressed data */
1614 if (efn->compression == 0)
1616 void *data_deciphered = NULL;
1617 unsigned int data_deciphered_sz = 0;
1618 /* if we alreayd have the data in ram... copy that */
1621 memcpy(data, efn->data, efn->size);
1623 if (!read_data_from_disk(ef, efn, data, size))
1625 if (efn->ciphered && cipher_key)
1627 if (eet_decipher(data, size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
1629 if (data_deciphered) free(data_deciphered);
1633 data = data_deciphered;
1634 size = data_deciphered_sz;
1637 /* compressed data */
1641 void *data_deciphered = NULL;
1642 unsigned int data_deciphered_sz = 0;
1644 int compr_size = efn->size;
1647 /* if we already have the data in ram... copy that */
1649 tmp_data = efn->data;
1652 tmp_data = malloc(compr_size);
1658 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1665 if (efn->ciphered && cipher_key)
1667 if (eet_decipher(tmp_data, compr_size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
1669 if (free_tmp) free(tmp_data);
1670 if (data_deciphered) free(data_deciphered);
1674 tmp_data = data_deciphered;
1675 compr_size = data_deciphered_sz;
1680 if (uncompress((Bytef *)data, &dlen,
1681 tmp_data, (uLongf)compr_size))
1695 if (data[size - 1] != '\0')
1698 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1705 /* fill in return values */
1718 eet_read(Eet_File *ef, const char *name, int *size_ret)
1720 return eet_read_cipher(ef, name, size_ret, NULL);
1724 eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
1727 const char *data = NULL;
1733 /* check to see its' an eet file pointer */
1734 if (eet_check_pointer(ef))
1738 if ((ef->mode != EET_FILE_MODE_READ) &&
1739 (ef->mode != EET_FILE_MODE_READ_WRITE))
1742 /* no header, return NULL */
1743 if (eet_check_header(ef))
1748 /* hunt hash bucket */
1749 efn = find_node_by_name(ef, name);
1750 if (!efn) goto on_error;
1752 if (efn->offset < 0 && efn->data == NULL)
1755 /* get size (uncompressed, if compressed at all) */
1756 size = efn->data_size;
1760 data = efn->data ? efn->data : ef->data + efn->offset;
1762 /* handle alias case */
1763 if (efn->compression)
1766 int compr_size = efn->size;
1769 tmp = alloca(sizeof (compr_size));
1772 if (uncompress((Bytef *)tmp, &dlen, (Bytef *) data, (uLongf)compr_size))
1775 if (tmp[compr_size - 1] != '\0')
1778 return eet_read_direct(ef, tmp, size_ret);
1781 if (!data) goto on_error;
1782 if (data[size - 1] != '\0') goto on_error;
1784 return eet_read_direct(ef, data, size_ret);
1787 /* uncompressed data */
1788 if (efn->compression == 0
1789 && efn->ciphered == 0)
1790 data = efn->data ? efn->data : ef->data + efn->offset;
1791 /* compressed data */
1795 /* fill in return values */
1809 eet_alias(Eet_File *ef, const char *name, const char *destination, int comp)
1813 Eina_Bool exists_already = EINA_FALSE;
1817 /* check to see its' an eet file pointer */
1818 if (eet_check_pointer(ef))
1820 if ((!name) || (!destination))
1822 if ((ef->mode != EET_FILE_MODE_WRITE) &&
1823 (ef->mode != EET_FILE_MODE_READ_WRITE))
1830 /* allocate header */
1831 ef->header = calloc(1, sizeof(Eet_File_Header));
1835 ef->header->magic = EET_MAGIC_FILE_HEADER;
1836 /* allocate directory block in ram */
1837 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1838 if (!ef->header->directory)
1845 /* 8 bit hash table (256 buckets) */
1846 ef->header->directory->size = 8;
1847 /* allocate base hash table */
1848 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1849 if (!ef->header->directory->nodes)
1851 free(ef->header->directory);
1857 /* figure hash bucket */
1858 hash = _eet_hash_gen(name, ef->header->directory->size);
1861 12 + (((strlen(destination) + 1) * 101) / 100)
1862 : strlen(destination) + 1;
1864 data2 = malloc(data_size);
1865 if (!data2) goto on_error;
1867 /* if we want to compress */
1872 /* compress the data with max compression */
1873 buflen = (uLongf)data_size;
1874 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
1875 (uLong)strlen(destination) + 1, Z_BEST_COMPRESSION) != Z_OK)
1880 /* record compressed chunk size */
1881 data_size = (int)buflen;
1882 if (data_size < 0 || data_size >= (int) (strlen(destination) + 1))
1885 data_size = strlen(destination) + 1;
1891 data3 = realloc(data2, data_size);
1898 memcpy(data2, destination, data_size);
1900 /* Does this node already exist? */
1901 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
1904 if ((efn->name) && (eet_string_match(efn->name, name)))
1909 efn->compression = !!comp;
1910 efn->size = data_size;
1911 efn->data_size = strlen(destination) + 1;
1914 exists_already = EINA_TRUE;
1918 if (!exists_already)
1920 efn = malloc(sizeof(Eet_File_Node));
1926 efn->name = strdup(name);
1927 efn->name_size = strlen(efn->name) + 1;
1930 efn->next = ef->header->directory->nodes[hash];
1931 ef->header->directory->nodes[hash] = efn;
1935 efn->compression = !!comp;
1936 efn->size = data_size;
1937 efn->data_size = strlen(destination) + 1;
1941 /* flags that writes are pending */
1942 ef->writes_pending = 1;
1953 eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int comp, const char *cipher_key)
1957 int exists_already = 0;
1961 /* check to see its' an eet file pointer */
1962 if (eet_check_pointer(ef))
1964 if ((!name) || (!data) || (size <= 0))
1966 if ((ef->mode != EET_FILE_MODE_WRITE) &&
1967 (ef->mode != EET_FILE_MODE_READ_WRITE))
1974 /* allocate header */
1975 ef->header = calloc(1, sizeof(Eet_File_Header));
1979 ef->header->magic = EET_MAGIC_FILE_HEADER;
1980 /* allocate directory block in ram */
1981 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1982 if (!ef->header->directory)
1989 /* 8 bit hash table (256 buckets) */
1990 ef->header->directory->size = 8;
1991 /* allocate base hash table */
1992 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1993 if (!ef->header->directory->nodes)
1995 free(ef->header->directory);
2001 /* figure hash bucket */
2002 hash = _eet_hash_gen(name, ef->header->directory->size);
2004 data_size = comp ? 12 + ((size * 101) / 100) : size;
2006 if (comp || !cipher_key)
2008 data2 = malloc(data_size);
2009 if (!data2) goto on_error;
2012 /* if we want to compress */
2017 /* compress the data with max compression */
2018 buflen = (uLongf)data_size;
2019 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2020 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2025 /* record compressed chunk size */
2026 data_size = (int)buflen;
2027 if (data_size < 0 || data_size >= size)
2036 data3 = realloc(data2, data_size);
2044 void *data_ciphered = NULL;
2045 unsigned int data_ciphered_sz = 0;
2048 tmp = data2 ? data2 : data;
2049 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key), &data_ciphered, &data_ciphered_sz))
2051 if (data2) free(data2);
2052 data2 = data_ciphered;
2053 data_size = data_ciphered_sz;
2054 size = (data_size > size) ? data_size : size;
2058 if (data_ciphered) free(data_ciphered);
2064 memcpy(data2, data, size);
2066 /* Does this node already exist? */
2067 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2070 if ((efn->name) && (eet_string_match(efn->name, name)))
2074 efn->ciphered = cipher_key ? 1 : 0;
2075 efn->compression = !!comp;
2076 efn->size = data_size;
2077 efn->data_size = size;
2084 if (!exists_already)
2086 efn = malloc(sizeof(Eet_File_Node));
2092 efn->name = strdup(name);
2093 efn->name_size = strlen(efn->name) + 1;
2096 efn->next = ef->header->directory->nodes[hash];
2097 ef->header->directory->nodes[hash] = efn;
2100 efn->ciphered = cipher_key ? 1 : 0;
2101 efn->compression = !!comp;
2102 efn->size = data_size;
2103 efn->data_size = size;
2107 /* flags that writes are pending */
2108 ef->writes_pending = 1;
2118 eet_write(Eet_File *ef, const char *name, const void *data, int size, int comp)
2120 return eet_write_cipher(ef, name, data, size, comp, NULL);
2124 eet_delete(Eet_File *ef, const char *name)
2127 Eet_File_Node *pefn;
2129 int exists_already = 0;
2131 /* check to see its' an eet file pointer */
2132 if (eet_check_pointer(ef))
2137 /* deleting keys is only possible in RW or WRITE mode */
2138 if (ef->mode == EET_FILE_MODE_READ)
2141 if (eet_check_header(ef))
2146 /* figure hash bucket */
2147 hash = _eet_hash_gen(name, ef->header->directory->size);
2149 /* Does this node already exist? */
2150 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2152 pefn = efn, efn = efn->next)
2155 if (eet_string_match(efn->name, name))
2161 ef->header->directory->nodes[hash] = efn->next;
2163 pefn->next = efn->next;
2165 if (efn->free_name) free(efn->name);
2171 /* flags that writes are pending */
2173 ef->writes_pending = 1;
2177 /* update access time */
2178 return exists_already;
2181 EAPI Eet_Dictionary *
2182 eet_dictionary_get(Eet_File *ef)
2184 if (eet_check_pointer(ef)) return NULL;
2191 eet_list(Eet_File *ef, const char *glob, int *count_ret)
2194 char **list_ret = NULL;
2196 int list_count_alloc = 0;
2199 /* check to see its' an eet file pointer */
2200 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2202 ((ef->mode != EET_FILE_MODE_READ) &&
2203 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2211 if (!strcmp(glob, "*")) glob = NULL;
2215 /* loop through all entries */
2216 num = (1 << ef->header->directory->size);
2217 for (i = 0; i < num; i++)
2219 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2221 /* if the entry matches the input glob
2222 * check for * explicitly, because on some systems, * isn't well
2225 if ((!glob) || !fnmatch(glob, efn->name, 0))
2227 /* add it to our list */
2230 /* only realloc in 32 entry chunks */
2231 if (list_count > list_count_alloc)
2233 char **new_list = NULL;
2235 list_count_alloc += 64;
2236 new_list = realloc(list_ret, list_count_alloc * (sizeof(char *)));
2243 list_ret = new_list;
2246 /* put pointer of name string in */
2247 list_ret[list_count - 1] = efn->name;
2254 /* return count and list */
2256 *count_ret = list_count;
2270 eet_num_entries(Eet_File *ef)
2272 int i, num, ret = 0;
2275 /* check to see its' an eet file pointer */
2276 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2277 ((ef->mode != EET_FILE_MODE_READ) &&
2278 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2283 /* loop through all entries */
2284 num = (1 << ef->header->directory->size);
2285 for (i = 0; i < num; i++)
2287 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2296 static Eet_File_Node *
2297 find_node_by_name(Eet_File *ef, const char *name)
2302 /* get hash bucket this should be in */
2303 hash = _eet_hash_gen(name, ef->header->directory->size);
2305 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2307 if (eet_string_match(efn->name, name))
2315 read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len)
2317 if (efn->offset < 0) return 0;
2321 if ((efn->offset + len) > ef->data_size) return 0;
2322 memcpy(buf, ef->data + efn->offset, len);
2329 /* seek to data location */
2330 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2334 len = fread(buf, len, 1, ef->readfp);