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 /* ifdef HAVE_UNISTD_H */
41 #ifdef HAVE_NETINET_IN_H
42 # include <netinet/in.h>
43 #endif /* ifdef HAVE_NETINET_IN_H */
47 #endif /* ifdef HAVE_EVIL */
52 # include <gnutls/gnutls.h>
54 #endif /* ifdef HAVE_GNUTLS */
57 # include <openssl/err.h>
58 # include <openssl/evp.h>
59 #endif /* ifdef HAVE_OPENSSL */
61 #ifdef EINA_HAVE_THREADS
63 GCRY_THREAD_OPTION_PTHREAD_IMPL;
64 # endif /* ifdef HAVE_GNUTLS */
65 #endif /* ifdef EINA_HAVE_THREADS */
68 #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;
100 const void *signature;
108 unsigned long int data_size;
110 unsigned int signature_length;
115 unsigned char writes_pending : 1;
116 unsigned char delete_me_now : 1;
119 struct _Eet_File_Header
122 Eet_File_Directory *directory;
125 struct _Eet_File_Directory
128 Eet_File_Node **nodes;
131 struct _Eet_File_Node
135 Eet_File_Node *next; /* FIXME: make buckets linked lists */
137 unsigned long int offset;
138 unsigned long int dictionary_offset;
139 unsigned long int name_offset;
141 unsigned int name_size;
143 unsigned int data_size;
145 unsigned char free_name : 1;
146 unsigned char compression : 1;
147 unsigned char ciphered : 1;
148 unsigned char alias : 1;
153 /* NB: all int's are stored in network byte order on disk */
155 int magic; /* magic number ie 0x1ee7ff00 */
156 int num_directory_entries; /* number of directory entries to follow */
157 int bytes_directory_entries; /* bytes of directory entries to follow */
160 int offset; /* bytes offset into file for data chunk */
161 int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
162 int size; /* size of the data chunk */
163 int data_size; /* size of the (uncompressed) data chunk */
164 int name_size; /* length in bytes of the name field */
165 char name[name_size]; /* name string (variable length) and \0 terminated */
166 } directory[num_directory_entries];
167 /* and now startes the data stream... */
172 /* NB: all int's are stored in network byte order on disk */
174 int magic; /* magic number ie 0x1ee70f42 */
175 int num_directory_entries; /* number of directory entries to follow */
176 int num_dictionary_entries; /* number of dictionary entries to follow */
179 int data_offset; /* bytes offset into file for data chunk */
180 int size; /* size of the data chunk */
181 int data_size; /* size of the (uncompressed) data chunk */
182 int name_offset; /* bytes offset into file for name string */
183 int name_size; /* length in bytes of the name field */
184 int flags; /* bit flags - for now:
185 bit 0 => compresion on/off
186 bit 1 => ciphered on/off
189 } directory[num_directory_entries];
197 } dictionary[num_dictionary_entries];
198 /* now start the string stream. */
199 /* and right after them the data stream. */
200 int magic_sign; /* Optional, only if the eet file is signed. */
201 int signature_length; /* Signature length. */
202 int x509_length; /* Public certificate that signed the file. */
203 char signature[signature_length]; /* The signature. */
204 char x509[x509_length]; /* The public certificate. */
207 #define EET_FILE2_HEADER_COUNT 3
208 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
209 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
211 #define EET_FILE2_HEADER_SIZE (sizeof(int) *\
212 EET_FILE2_HEADER_COUNT)
213 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) *\
214 EET_FILE2_DIRECTORY_ENTRY_COUNT)
215 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) *\
216 EET_FILE2_DICTIONARY_ENTRY_COUNT)
218 /* prototypes of internal calls */
219 static Eet_File * eet_cache_find(const char *path,
222 static void eet_cache_add(Eet_File *ef,
226 static void eet_cache_del(Eet_File *ef,
230 static int eet_string_match(const char *s1, const char *s2);
232 static Eet_Error eet_flush(Eet_File *ef);
234 static Eet_Error eet_flush2(Eet_File *ef);
235 static Eet_File_Node * find_node_by_name(Eet_File *ef, const char *name);
236 static int read_data_from_disk(Eet_File *ef,
241 static Eet_Error eet_internal_close(Eet_File *ef, Eina_Bool locked);
243 static Eina_Lock eet_cache_lock;
245 #define LOCK_CACHE eina_lock_take(&eet_cache_lock)
246 #define UNLOCK_CACHE eina_lock_release(&eet_cache_lock)
248 #define INIT_FILE(File) eina_lock_new(&File->file_lock)
249 #define LOCK_FILE(File) eina_lock_take(&File->file_lock)
250 #define UNLOCK_FILE(File) eina_lock_release(&File->file_lock)
251 #define DESTROY_FILE(File) eina_lock_free(&File->file_lock)
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))
273 } /* eet_check_pointer */
276 eet_check_header(const Eet_File *ef)
281 if (!ef->header->directory)
285 } /* eet_check_header */
288 eet_test_close(int test,
293 ef->delete_me_now = 1;
294 eet_internal_close(ef, EINA_TRUE);
298 } /* eet_test_close */
300 /* find an eet file in the currently in use cache */
302 eet_cache_find(const char *path,
309 for (i = 0; i < cache_num; i++)
311 /* if matches real path - return it */
312 if (eet_string_match(cache[i]->path, path))
313 if (!cache[i]->delete_me_now)
320 } /* eet_cache_find */
322 /* add to end of cache */
323 /* this should only be called when the cache lock is already held */
325 eet_cache_add(Eet_File *ef,
330 Eet_File **new_cache;
334 new_cache_num = *cache_num;
335 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
337 Eet_File *del_ef = NULL;
341 for (i = 0; i < new_cache_num; i++)
343 if (new_cache[i]->references == 0)
345 del_ef = new_cache[i];
352 del_ef->delete_me_now = 1;
353 eet_internal_close(del_ef, EINA_TRUE);
358 new_cache_num = *cache_num;
359 new_cache_alloc = *cache_alloc;
361 if (new_cache_num > new_cache_alloc)
363 new_cache_alloc += 16;
364 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
367 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
372 new_cache[new_cache_num - 1] = ef;
374 *cache_num = new_cache_num;
375 *cache_alloc = new_cache_alloc;
376 } /* eet_cache_add */
378 /* delete from cache */
379 /* this should only be called when the cache lock is already held */
381 eet_cache_del(Eet_File *ef,
386 Eet_File **new_cache;
387 int new_cache_num, new_cache_alloc;
391 new_cache_num = *cache_num;
392 new_cache_alloc = *cache_alloc;
393 if (new_cache_num <= 0)
396 for (i = 0; i < new_cache_num; i++)
398 if (new_cache[i] == ef)
402 if (i >= new_cache_num)
406 for (j = i; j < new_cache_num; j++)
407 new_cache[j] = new_cache[j + 1];
409 if (new_cache_num <= (new_cache_alloc - 16))
411 new_cache_alloc -= 16;
412 if (new_cache_num > 0)
414 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
417 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
429 *cache_num = new_cache_num;
430 *cache_alloc = new_cache_alloc;
431 } /* eet_cache_del */
433 /* internal string match. null friendly, catches same ptr */
435 eet_string_match(const char *s1,
438 /* both null- no match */
445 return (!strcmp(s1, s2));
446 } /* eet_string_match */
448 /* flush out writes to a v2 eet file */
450 eet_flush2(Eet_File *ef)
454 Eet_Error error = EET_ERROR_NONE;
455 int head[EET_FILE2_HEADER_COUNT];
456 int num_directory_entries = 0;
457 int num_dictionary_entries = 0;
458 int bytes_directory_entries = 0;
459 int bytes_dictionary_entries = 0;
460 int bytes_strings = 0;
462 int strings_offset = 0;
467 if (eet_check_pointer(ef))
468 return EET_ERROR_BAD_OBJECT;
470 if (eet_check_header(ef))
471 return EET_ERROR_EMPTY;
473 if (!ef->writes_pending)
474 return EET_ERROR_NONE;
476 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
477 || (ef->mode == EET_FILE_MODE_WRITE))
481 /* opening for write - delete old copy of file right away */
483 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
484 fp = fdopen(fd, "wb");
486 return EET_ERROR_NOT_WRITABLE;
488 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
491 return EET_ERROR_NOT_WRITABLE;
493 /* calculate string base offset and data base offset */
494 num = (1 << ef->header->directory->size);
495 for (i = 0; i < num; ++i)
497 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
499 num_directory_entries++;
500 bytes_strings += strlen(efn->name) + 1;
505 num_dictionary_entries = ef->ed->count;
507 for (i = 0; i < num_dictionary_entries; ++i)
508 bytes_strings += ef->ed->all[i].len;
511 /* calculate section bytes size */
512 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
513 num_directory_entries + EET_FILE2_HEADER_SIZE;
514 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
515 num_dictionary_entries;
517 /* calculate per entry offset */
518 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
519 data_offset = bytes_directory_entries + bytes_dictionary_entries +
522 for (i = 0; i < num; ++i)
524 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
526 efn->offset = data_offset;
527 data_offset += efn->size;
529 efn->name_offset = strings_offset;
530 strings_offset += efn->name_size;
534 /* calculate dictionary strings offset */
536 ef->ed->offset = strings_offset;
538 /* go thru and write the header */
539 head[0] = (int)htonl((unsigned int)EET_MAGIC_FILE2);
540 head[1] = (int)htonl((unsigned int)num_directory_entries);
541 head[2] = (int)htonl((unsigned int)num_dictionary_entries);
543 fseek(fp, 0, SEEK_SET);
544 if (fwrite(head, sizeof (head), 1, fp) != 1)
547 /* write directories entry */
548 for (i = 0; i < num; i++)
550 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
553 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
555 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
557 ibuf[0] = (int)htonl((unsigned int)efn->offset);
558 ibuf[1] = (int)htonl((unsigned int)efn->size);
559 ibuf[2] = (int)htonl((unsigned int)efn->data_size);
560 ibuf[3] = (int)htonl((unsigned int)efn->name_offset);
561 ibuf[4] = (int)htonl((unsigned int)efn->name_size);
562 ibuf[5] = (int)htonl((unsigned int)flag);
564 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
569 /* write dictionnary */
572 int offset = strings_offset;
574 for (j = 0; j < ef->ed->count; ++j)
576 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
578 sbuf[0] = (int)htonl((unsigned int)ef->ed->all[j].hash);
579 sbuf[1] = (int)htonl((unsigned int)offset);
580 sbuf[2] = (int)htonl((unsigned int)ef->ed->all[j].len);
581 sbuf[3] = (int)htonl((unsigned int)ef->ed->all[j].prev);
582 sbuf[4] = (int)htonl((unsigned int)ef->ed->all[j].next);
584 offset += ef->ed->all[j].len;
586 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
591 /* write directories name */
592 for (i = 0; i < num; i++)
594 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
596 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
603 for (j = 0; j < ef->ed->count; ++j)
605 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
610 for (i = 0; i < num; i++)
612 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
614 if (fwrite(efn->data, efn->size, 1, fp) != 1)
619 /* flush all write to the file. */
621 // this is going to really cause trouble. if ANYTHING this needs to go into a
622 // thread spawned off - but even then...
623 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
624 // manual pages at eachother, but ext4 broke behavior that has been in place
625 // for decades and that 1000's of apps rely on daily - that is that one operation
626 // to disk is committed to disk BEFORE following operations, so the fs retains
627 // a consistent state
628 // fsync(fileno(fp));
630 /* append signature if required */
633 error = eet_identity_sign(fp, ef->key);
634 if (error != EET_ERROR_NONE)
638 /* no more writes pending */
639 ef->writes_pending = 0;
643 return EET_ERROR_NONE;
650 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
652 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
654 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
656 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
658 default: error = EET_ERROR_WRITE_ERROR; break;
670 if (++eet_init_count != 1)
671 return eet_init_count;
675 fprintf(stderr, "Eet: Eina init failed");
676 return --eet_init_count;
679 _eet_log_dom_global = eina_log_domain_register("eet", EET_DEFAULT_LOG_COLOR);
680 if (_eet_log_dom_global < 0)
682 EINA_LOG_ERR("Eet Can not create a general log domain.");
686 eina_lock_new(&eet_cache_lock);
688 if (!eet_node_init())
690 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
691 goto unregister_log_domain;
695 /* Before the library can be used, it must initialize itself if needed. */
696 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
698 gcry_check_version(NULL);
699 /* Disable warning messages about problems with the secure memory subsystem.
700 This command should be run right after gcry_check_version. */
701 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
702 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
703 enabling the use of secure memory. It also drops all extra privileges the
704 process has (i.e. if it is run as setuid (root)). If the argument nbytes
705 is 0, secure memory will be disabled. The minimum amount of secure memory
706 allocated is currently 16384 bytes; you may thus use a value of 1 to
707 request that default size. */
709 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
711 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
714 # ifdef EINA_HAVE_THREADS
715 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
717 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
719 # endif /* ifdef EINA_HAVE_THREADS */
720 if (gnutls_global_init())
723 #endif /* ifdef HAVE_GNUTLS */
725 ERR_load_crypto_strings();
726 OpenSSL_add_all_algorithms();
727 #endif /* ifdef HAVE_OPENSSL */
729 return eet_init_count;
735 unregister_log_domain:
736 eina_log_domain_unregister(_eet_log_dom_global);
737 _eet_log_dom_global = -1;
740 return --eet_init_count;
746 if (--eet_init_count != 0)
747 return eet_init_count;
752 eina_lock_free(&eet_cache_lock);
755 gnutls_global_deinit();
756 #endif /* ifdef HAVE_GNUTLS */
760 #endif /* ifdef HAVE_OPENSSL */
761 eina_log_domain_unregister(_eet_log_dom_global);
762 _eet_log_dom_global = -1;
765 return eet_init_count;
769 eet_sync(Eet_File *ef)
773 if (eet_check_pointer(ef))
774 return EET_ERROR_BAD_OBJECT;
776 if ((ef->mode != EET_FILE_MODE_WRITE) &&
777 (ef->mode != EET_FILE_MODE_READ_WRITE))
778 return EET_ERROR_NOT_WRITABLE;
780 if (!ef->writes_pending)
781 return EET_ERROR_NONE;
785 ret = eet_flush2(ef);
798 * We need to compute the list of eet file to close separately from the cache,
799 * due to eet_close removing them from the cache after each call.
802 for (i = 0; i < eet_writers_num; i++)
804 if (eet_writers[i]->references <= 0)
808 for (i = 0; i < eet_readers_num; i++)
810 if (eet_readers[i]->references <= 0)
816 Eet_File **closelist = NULL;
818 closelist = alloca(num * sizeof(Eet_File *));
820 for (i = 0; i < eet_writers_num; i++)
822 if (eet_writers[i]->references <= 0)
824 closelist[num] = eet_writers[i];
825 eet_writers[i]->delete_me_now = 1;
830 for (i = 0; i < eet_readers_num; i++)
832 if (eet_readers[i]->references <= 0)
834 closelist[num] = eet_readers[i];
835 eet_readers[i]->delete_me_now = 1;
840 for (i = 0; i < num; i++)
842 eet_internal_close(closelist[i], EINA_TRUE);
847 } /* eet_clearcache */
849 /* FIXME: MMAP race condition in READ_WRITE_MODE */
851 eet_internal_read2(Eet_File *ef)
853 const int *data = (const int *)ef->data;
854 const char *start = (const char *)ef->data;
856 unsigned long int bytes_directory_entries;
857 unsigned long int bytes_dictionary_entries;
858 unsigned long int signature_base_offset;
859 unsigned long int num_directory_entries;
860 unsigned long int num_dictionary_entries;
864 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
869 #define GET_INT(Value, Pointer, Index)\
871 Value = ntohl(*Pointer);\
873 Index += sizeof(int);\
876 /* get entries count and byte count */
877 GET_INT(num_directory_entries, data, idx);
878 /* get dictionary count and byte count */
879 GET_INT(num_dictionary_entries, data, idx);
881 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
882 num_directory_entries + EET_FILE2_HEADER_SIZE;
883 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
884 num_dictionary_entries;
886 /* we can't have <= 0 values here - invalid */
887 if (eet_test_close((num_directory_entries <= 0), ef))
890 /* we can't have more bytes directory and bytes in dictionaries than the size of the file */
891 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
895 /* allocate header */
896 ef->header = calloc(1, sizeof(Eet_File_Header));
897 if (eet_test_close(!ef->header, ef))
900 ef->header->magic = EET_MAGIC_FILE_HEADER;
902 /* allocate directory block in ram */
903 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
904 if (eet_test_close(!ef->header->directory, ef))
907 /* 8 bit hash table (256 buckets) */
908 ef->header->directory->size = 8;
909 /* allocate base hash table */
910 ef->header->directory->nodes =
911 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
912 if (eet_test_close(!ef->header->directory->nodes, ef))
915 signature_base_offset = 0;
917 /* actually read the directory block - all of it, into ram */
918 for (i = 0; i < num_directory_entries; ++i)
922 unsigned long int name_offset;
923 unsigned long int name_size;
927 /* out directory block is inconsistent - we have overrun our */
928 /* dynamic block buffer before we finished scanning dir entries */
929 efn = malloc(sizeof(Eet_File_Node));
930 if (eet_test_close(!efn, ef))
932 if (efn) free(efn); /* yes i know - we only get here if
933 * efn is null/0 -> trying to shut up
934 * warning tools like cppcheck */
938 /* get entrie header */
939 GET_INT(efn->offset, data, idx);
940 GET_INT(efn->size, data, idx);
941 GET_INT(efn->data_size, data, idx);
942 GET_INT(name_offset, data, idx);
943 GET_INT(name_size, data, idx);
944 GET_INT(flag, data, idx);
946 efn->compression = flag & 0x1 ? 1 : 0;
947 efn->ciphered = flag & 0x2 ? 1 : 0;
948 efn->alias = flag & 0x4 ? 1 : 0;
950 #define EFN_TEST(Test, Ef, Efn)\
951 if (eet_test_close(Test, Ef))\
957 /* check data pointer position */
958 EFN_TEST(!((efn->size > 0)
959 && (efn->offset + efn->size <= ef->data_size)
960 && (efn->offset > bytes_dictionary_entries +
961 bytes_directory_entries)), ef, efn);
963 /* check name position */
964 EFN_TEST(!((name_size > 0)
965 && (name_offset + name_size < ef->data_size)
966 && (name_offset >= bytes_dictionary_entries +
967 bytes_directory_entries)), ef, efn);
969 name = start + name_offset;
971 /* check '\0' at the end of name string */
972 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
975 efn->name = (char *)name;
976 efn->name_size = name_size;
978 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
979 efn->next = ef->header->directory->nodes[hash];
980 ef->header->directory->nodes[hash] = efn;
982 /* read-only mode, so currently we have no data loaded */
983 if (ef->mode == EET_FILE_MODE_READ)
984 efn->data = NULL; /* read-write mode - read everything into ram */
987 efn->data = malloc(efn->size);
989 memcpy(efn->data, ef->data + efn->offset, efn->size);
992 /* compute the possible position of a signature */
993 if (signature_base_offset < efn->offset + efn->size)
994 signature_base_offset = efn->offset + efn->size;
999 if (num_dictionary_entries)
1001 const int *dico = (const int *)ef->data +
1002 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1003 EET_FILE2_HEADER_COUNT;
1006 if (eet_test_close((num_dictionary_entries *
1007 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1008 (bytes_dictionary_entries + bytes_directory_entries),
1012 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1013 if (eet_test_close(!ef->ed, ef))
1016 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1017 if (eet_test_close(!ef->ed->all, ef))
1020 ef->ed->count = num_dictionary_entries;
1021 ef->ed->total = num_dictionary_entries;
1022 ef->ed->start = start + bytes_dictionary_entries +
1023 bytes_directory_entries;
1024 ef->ed->end = ef->ed->start;
1026 for (j = 0; j < ef->ed->count; ++j)
1028 unsigned int offset;
1031 GET_INT(hash, dico, idx);
1032 GET_INT(offset, dico, idx);
1033 GET_INT(ef->ed->all[j].len, dico, idx);
1034 GET_INT(ef->ed->all[j].prev, dico, idx);
1035 GET_INT(ef->ed->all[j].next, dico, idx);
1037 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1038 So stick to int and check the value. */
1039 if (eet_test_close(hash & 0xFFFFFF00, ef))
1042 /* Check string position */
1043 if (eet_test_close(!((ef->ed->all[j].len > 0)
1045 (bytes_dictionary_entries +
1046 bytes_directory_entries))
1047 && (offset + ef->ed->all[j].len <
1048 ef->data_size)), ef))
1051 ef->ed->all[j].str = start + offset;
1053 if (ef->ed->all[j].str + ef->ed->all[j].len > ef->ed->end)
1054 ef->ed->end = ef->ed->all[j].str + ef->ed->all[j].len;
1056 /* Check '\0' at the end of the string */
1057 if (eet_test_close(ef->ed->all[j].str[ef->ed->all[j].len - 1] !=
1061 ef->ed->all[j].hash = hash;
1062 if (ef->ed->all[j].prev == -1)
1063 ef->ed->hash[hash] = j;
1065 /* compute the possible position of a signature */
1066 if (signature_base_offset < offset + ef->ed->all[j].len)
1067 signature_base_offset = offset + ef->ed->all[j].len;
1071 /* Check if the file is signed */
1072 ef->x509_der = NULL;
1073 ef->x509_length = 0;
1074 ef->signature = NULL;
1075 ef->signature_length = 0;
1077 if (signature_base_offset < ef->data_size)
1079 #ifdef HAVE_SIGNATURE
1080 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1081 signature_base_offset;
1082 ef->x509_der = eet_identity_check(ef->data,
1083 signature_base_offset,
1087 ef->data_size - signature_base_offset,
1089 &ef->signature_length,
1092 if (eet_test_close(!ef->x509_der, ef))
1095 #else /* ifdef HAVE_SIGNATURE */
1097 "This file could be signed but you didn't compile the necessary code to check the signature.");
1098 #endif /* ifdef HAVE_SIGNATURE */
1102 } /* eet_internal_read2 */
1104 #if EET_OLD_EET_FILE_FORMAT
1106 eet_internal_read1(Eet_File *ef)
1108 const unsigned char *dyn_buf = NULL;
1109 const unsigned char *p = NULL;
1110 unsigned long int byte_entries;
1111 unsigned long int num_entries;
1116 "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.",
1119 /* build header table if read mode */
1122 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1125 #define EXTRACT_INT(Value, Pointer, Index)\
1128 memcpy(&tmp, Pointer + Index, sizeof(int));\
1129 Value = ntohl(tmp);\
1130 Index += sizeof(int);\
1133 /* get entries count and byte count */
1134 EXTRACT_INT(num_entries, ef->data, idx);
1135 EXTRACT_INT(byte_entries, ef->data, idx);
1137 /* we can't have <= 0 values here - invalid */
1138 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1141 /* we can't have more entires than minimum bytes for those! invalid! */
1142 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1145 /* check we will not outrun the file limit */
1146 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1150 /* allocate header */
1151 ef->header = calloc(1, sizeof(Eet_File_Header));
1152 if (eet_test_close(!ef->header, ef))
1155 ef->header->magic = EET_MAGIC_FILE_HEADER;
1157 /* allocate directory block in ram */
1158 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1159 if (eet_test_close(!ef->header->directory, ef))
1162 /* 8 bit hash table (256 buckets) */
1163 ef->header->directory->size = 8;
1164 /* allocate base hash table */
1165 ef->header->directory->nodes =
1166 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1167 if (eet_test_close(!ef->header->directory->nodes, ef))
1170 /* actually read the directory block - all of it, into ram */
1171 dyn_buf = ef->data + idx;
1173 /* parse directory block */
1176 for (i = 0; i < num_entries; i++)
1185 #define HEADER_SIZE (sizeof(int) * 5)
1187 /* out directory block is inconsistent - we have overrun our */
1188 /* dynamic block buffer before we finished scanning dir entries */
1189 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1192 /* allocate all the ram needed for this stored node accounting */
1193 efn = malloc (sizeof(Eet_File_Node));
1194 if (eet_test_close(!efn, ef))
1196 if (efn) free(efn); /* yes i know - we only get here if
1197 * efn is null/0 -> trying to shut up
1198 * warning tools like cppcheck */
1202 /* get entrie header */
1203 EXTRACT_INT(efn->offset, p, indexn);
1204 EXTRACT_INT(efn->compression, p, indexn);
1205 EXTRACT_INT(efn->size, p, indexn);
1206 EXTRACT_INT(efn->data_size, p, indexn);
1207 EXTRACT_INT(name_size, p, indexn);
1209 efn->name_size = name_size;
1214 if (eet_test_close(efn->size <= 0, ef))
1220 /* invalid name_size */
1221 if (eet_test_close(name_size <= 0, ef))
1227 /* reading name would mean falling off end of dyn_buf - invalid */
1228 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1234 /* This code is useless if we dont want backward compatibility */
1236 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1239 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1243 efn->name = malloc(sizeof(char) * name_size + 1);
1244 if (eet_test_close(!efn->name, ef))
1250 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1251 efn->name[name_size] = 0;
1254 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1259 /* The only really useful peace of code for efn->name (no backward compatibility) */
1260 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1262 /* get hash bucket it should go in */
1263 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1264 efn->next = ef->header->directory->nodes[hash];
1265 ef->header->directory->nodes[hash] = efn;
1267 /* read-only mode, so currently we have no data loaded */
1268 if (ef->mode == EET_FILE_MODE_READ)
1269 efn->data = NULL; /* read-write mode - read everything into ram */
1272 data = malloc(efn->size);
1274 memcpy(data, ef->data + efn->offset, efn->size);
1280 p += HEADER_SIZE + name_size;
1283 } /* eet_internal_read1 */
1285 #endif /* if EET_OLD_EET_FILE_FORMAT */
1288 * this should only be called when the cache lock is already held
1289 * (We could drop this restriction if we add a parameter to eet_test_close
1290 * that indicates if the lock is held or not. For now it is easiest
1291 * to just require that it is always held.)
1294 eet_internal_read(Eet_File *ef)
1296 const int *data = (const int *)ef->data;
1298 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1301 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1304 switch (ntohl(*data))
1306 #if EET_OLD_EET_FILE_FORMAT
1307 case EET_MAGIC_FILE:
1308 return eet_internal_read1(ef);
1310 #endif /* if EET_OLD_EET_FILE_FORMAT */
1311 case EET_MAGIC_FILE2:
1312 return eet_internal_read2(ef);
1315 ef->delete_me_now = 1;
1316 eet_internal_close(ef, EINA_TRUE);
1321 } /* eet_internal_read */
1324 eet_internal_close(Eet_File *ef,
1329 /* check to see its' an eet file pointer */
1330 if (eet_check_pointer(ef))
1331 return EET_ERROR_BAD_OBJECT;
1338 /* if its still referenced - dont go any further */
1339 if (ef->references > 0)
1341 /* flush any writes */
1342 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1343 (ef->mode == EET_FILE_MODE_READ_WRITE))
1348 err = eet_flush2(ef);
1350 eet_identity_unref(ef->key);
1353 /* if not urgent to delete it - dont free it - leave it in cache */
1354 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1357 /* remove from cache */
1358 if (ef->mode == EET_FILE_MODE_READ)
1359 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1360 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1361 (ef->mode == EET_FILE_MODE_READ_WRITE))
1362 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1364 /* we can unlock the cache now */
1373 if (ef->header->directory)
1375 if (ef->header->directory->nodes)
1379 num = (1 << ef->header->directory->size);
1380 for (i = 0; i < num; i++)
1384 while ((efn = ef->header->directory->nodes[i]))
1389 ef->header->directory->nodes[i] = efn->next;
1397 free(ef->header->directory->nodes);
1400 free(ef->header->directory);
1406 eet_dictionary_free(ef->ed);
1414 eina_file_map_free(ef->readfp, (void *) ef->data);
1416 eina_file_close(ef->readfp);
1419 /* zero out ram for struct - caution tactic against stale memory use */
1420 memset(ef, 0, sizeof(Eet_File));
1430 return EET_ERROR_NONE;
1431 } /* eet_internal_close */
1434 eet_memopen_read(const void *data,
1439 if (!data || size == 0)
1442 ef = malloc (sizeof (Eet_File));
1450 ef->magic = EET_MAGIC_FILE;
1452 ef->mode = EET_FILE_MODE_READ;
1454 ef->delete_me_now = 1;
1457 ef->data_size = size;
1459 ef->sha1_length = 0;
1461 /* eet_internal_read expects the cache lock to be held when it is called */
1463 ef = eet_internal_read(ef);
1466 } /* eet_memopen_read */
1469 eet_open(const char *file,
1475 unsigned long int size;
1480 /* find the current file handle in cache*/
1483 if (mode == EET_FILE_MODE_READ)
1485 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1490 ef->delete_me_now = 1;
1491 eet_internal_close(ef, EINA_TRUE);
1494 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1496 else if ((mode == EET_FILE_MODE_WRITE) ||
1497 (mode == EET_FILE_MODE_READ_WRITE))
1499 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1502 ef->delete_me_now = 1;
1504 eet_internal_close(ef, EINA_TRUE);
1507 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1510 /* try open the file based on mode */
1511 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1513 /* Prevent garbage in futur comparison. */
1514 fp = eina_file_open(file, EINA_FALSE);
1518 size = eina_file_size_get(fp);
1520 if (size < ((int)sizeof(int) * 3))
1522 eina_file_close(fp);
1531 if (!fp && mode == EET_FILE_MODE_READ)
1536 if (mode != EET_FILE_MODE_WRITE)
1545 if (ef && ef->readfp != fp)
1547 ef->delete_me_now = 1;
1549 eet_internal_close(ef, EINA_TRUE);
1555 /* reference it up and return it */
1557 eina_file_close(fp);
1564 file_len = strlen(file) + 1;
1566 /* Allocate struct for eet file and have it zero'd out */
1567 ef = malloc(sizeof(Eet_File) + file_len);
1571 /* fill some of the members */
1575 ef->path = ((char *)ef) + sizeof(Eet_File);
1576 memcpy(ef->path, file, file_len);
1577 ef->magic = EET_MAGIC_FILE;
1581 ef->writes_pending = 0;
1582 ef->delete_me_now = 0;
1586 ef->sha1_length = 0;
1588 ef->ed = (mode == EET_FILE_MODE_WRITE)
1589 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1590 eet_dictionary_add() : NULL;
1593 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1596 /* if we can't open - bail out */
1597 if (eet_test_close(!ef->readfp, ef))
1600 /* if we opened for read or read-write */
1601 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1603 ef->data_size = size;
1604 ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL);
1605 if (eet_test_close((ef->data == NULL), ef))
1608 ef = eet_internal_read(ef);
1615 if (ef->references == 1)
1617 if (ef->mode == EET_FILE_MODE_READ)
1618 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1619 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1620 (ef->mode == EET_FILE_MODE_READ_WRITE))
1621 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1633 eet_mode_get(Eet_File *ef)
1635 /* check to see its' an eet file pointer */
1636 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1637 return EET_FILE_MODE_INVALID;
1640 } /* eet_mode_get */
1643 eet_identity_x509(Eet_File *ef,
1650 *der_length = ef->x509_length;
1652 return ef->x509_der;
1653 } /* eet_identity_x509 */
1656 eet_identity_signature(Eet_File *ef,
1657 int *signature_length)
1662 if (signature_length)
1663 *signature_length = ef->signature_length;
1665 return ef->signature;
1666 } /* eet_identity_signature */
1669 eet_identity_sha1(Eet_File *ef,
1673 ef->sha1 = eet_identity_compute_sha1(ef->data,
1678 *sha1_length = ef->sha1_length;
1681 } /* eet_identity_sha1 */
1684 eet_identity_set(Eet_File *ef,
1690 return EET_ERROR_BAD_OBJECT;
1694 eet_identity_ref(ef->key);
1695 eet_identity_unref(tmp);
1697 /* flags that writes are pending */
1698 ef->writes_pending = 1;
1700 return EET_ERROR_NONE;
1701 } /* eet_identity_set */
1704 eet_close(Eet_File *ef)
1706 return eet_internal_close(ef, EINA_FALSE);
1710 eet_read_cipher(Eet_File *ef,
1713 const char *cipher_key)
1717 unsigned long int size = 0;
1722 /* check to see its' an eet file pointer */
1723 if (eet_check_pointer(ef))
1729 if ((ef->mode != EET_FILE_MODE_READ) &&
1730 (ef->mode != EET_FILE_MODE_READ_WRITE))
1733 /* no header, return NULL */
1734 if (eet_check_header(ef))
1739 /* hunt hash bucket */
1740 efn = find_node_by_name(ef, name);
1744 /* get size (uncompressed, if compressed at all) */
1745 size = efn->data_size;
1748 data = malloc(size);
1752 /* uncompressed data */
1753 if (efn->compression == 0)
1755 void *data_deciphered = NULL;
1756 unsigned int data_deciphered_sz = 0;
1757 /* if we already have the data in ram... copy that */
1759 if (efn->ciphered && efn->size > size)
1762 data = realloc(data, efn->size);
1766 memcpy(data, efn->data, size);
1768 if (!read_data_from_disk(ef, efn, data, size))
1771 if (efn->ciphered && cipher_key)
1773 if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key),
1774 &data_deciphered, &data_deciphered_sz))
1776 if (data_deciphered)
1777 free(data_deciphered);
1783 data = data_deciphered;
1784 size = data_deciphered_sz;
1787 /* compressed data */
1790 void *tmp_data = NULL;
1791 void *data_deciphered = NULL;
1792 unsigned int data_deciphered_sz = 0;
1794 int compr_size = efn->size;
1797 /* if we already have the data in ram... copy that */
1799 tmp_data = efn->data;
1802 tmp_data = malloc(compr_size);
1808 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1815 if (efn->ciphered && cipher_key)
1817 if (eet_decipher(tmp_data, compr_size, cipher_key,
1818 strlen(cipher_key), &data_deciphered,
1819 &data_deciphered_sz))
1824 if (data_deciphered)
1825 free(data_deciphered);
1833 tmp_data = data_deciphered;
1834 compr_size = data_deciphered_sz;
1839 if (uncompress((Bytef *)data, &dlen,
1840 tmp_data, (uLongf)compr_size))
1858 if (data[size - 1] != '\0')
1861 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1868 /* fill in return values */
1878 } /* eet_read_cipher */
1881 eet_read(Eet_File *ef,
1885 return eet_read_cipher(ef, name, size_ret, NULL);
1889 eet_read_direct(Eet_File *ef,
1894 const char *data = NULL;
1900 /* check to see its' an eet file pointer */
1901 if (eet_check_pointer(ef))
1907 if ((ef->mode != EET_FILE_MODE_READ) &&
1908 (ef->mode != EET_FILE_MODE_READ_WRITE))
1911 /* no header, return NULL */
1912 if (eet_check_header(ef))
1917 /* hunt hash bucket */
1918 efn = find_node_by_name(ef, name);
1922 /* trick to detect data in memory instead of mmaped from disk */
1923 if (efn->offset > ef->data_size && !efn->data)
1926 /* get size (uncompressed, if compressed at all) */
1927 size = efn->data_size;
1931 data = efn->data ? efn->data : ef->data + efn->offset;
1933 /* handle alias case */
1934 if (efn->compression)
1937 int compr_size = efn->size;
1940 tmp = alloca(sizeof (compr_size));
1943 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1944 (uLongf)compr_size))
1947 if (tmp[compr_size - 1] != '\0')
1952 return eet_read_direct(ef, tmp, size_ret);
1958 if (data[size - 1] != '\0')
1963 return eet_read_direct(ef, data, size_ret);
1966 /* uncompressed data */
1967 if (efn->compression == 0
1968 && efn->ciphered == 0)
1969 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1973 /* fill in return values */
1984 } /* eet_read_direct */
1987 eet_alias(Eet_File *ef,
1989 const char *destination,
1994 Eina_Bool exists_already = EINA_FALSE;
1998 /* check to see its' an eet file pointer */
1999 if (eet_check_pointer(ef))
2002 if ((!name) || (!destination))
2005 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2006 (ef->mode != EET_FILE_MODE_READ_WRITE))
2013 /* allocate header */
2014 ef->header = calloc(1, sizeof(Eet_File_Header));
2018 ef->header->magic = EET_MAGIC_FILE_HEADER;
2019 /* allocate directory block in ram */
2020 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2021 if (!ef->header->directory)
2028 /* 8 bit hash table (256 buckets) */
2029 ef->header->directory->size = 8;
2030 /* allocate base hash table */
2031 ef->header->directory->nodes =
2032 calloc(1, sizeof(Eet_File_Node *) *
2033 (1 << ef->header->directory->size));
2034 if (!ef->header->directory->nodes)
2036 free(ef->header->directory);
2042 /* figure hash bucket */
2043 hash = _eet_hash_gen(name, ef->header->directory->size);
2046 12 + (((strlen(destination) + 1) * 101) / 100)
2047 : strlen(destination) + 1;
2049 data2 = malloc(data_size);
2053 /* if we want to compress */
2058 /* compress the data with max compression */
2059 buflen = (uLongf)data_size;
2060 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2061 (uLong)strlen(destination) + 1,
2062 Z_BEST_COMPRESSION) != Z_OK)
2068 /* record compressed chunk size */
2069 data_size = (int)buflen;
2070 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2073 data_size = strlen(destination) + 1;
2079 data3 = realloc(data2, data_size);
2086 memcpy(data2, destination, data_size);
2088 /* Does this node already exist? */
2089 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2092 if ((efn->name) && (eet_string_match(efn->name, name)))
2097 efn->compression = !!comp;
2098 efn->size = data_size;
2099 efn->data_size = strlen(destination) + 1;
2101 /* Put the offset above the limit to avoid direct access */
2102 efn->offset = ef->data_size + 1;
2103 exists_already = EINA_TRUE;
2108 if (!exists_already)
2110 efn = malloc(sizeof(Eet_File_Node));
2117 efn->name = strdup(name);
2118 efn->name_size = strlen(efn->name) + 1;
2121 efn->next = ef->header->directory->nodes[hash];
2122 ef->header->directory->nodes[hash] = efn;
2123 /* Put the offset above the limit to avoid direct access */
2124 efn->offset = ef->data_size + 1;
2127 efn->compression = !!comp;
2128 efn->size = data_size;
2129 efn->data_size = strlen(destination) + 1;
2133 /* flags that writes are pending */
2134 ef->writes_pending = 1;
2145 eet_write_cipher(Eet_File *ef,
2150 const char *cipher_key)
2154 int exists_already = 0;
2158 /* check to see its' an eet file pointer */
2159 if (eet_check_pointer(ef))
2162 if ((!name) || (!data) || (size <= 0))
2165 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2166 (ef->mode != EET_FILE_MODE_READ_WRITE))
2173 /* allocate header */
2174 ef->header = calloc(1, sizeof(Eet_File_Header));
2178 ef->header->magic = EET_MAGIC_FILE_HEADER;
2179 /* allocate directory block in ram */
2180 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2181 if (!ef->header->directory)
2188 /* 8 bit hash table (256 buckets) */
2189 ef->header->directory->size = 8;
2190 /* allocate base hash table */
2191 ef->header->directory->nodes =
2192 calloc(1, sizeof(Eet_File_Node *) *
2193 (1 << ef->header->directory->size));
2194 if (!ef->header->directory->nodes)
2196 free(ef->header->directory);
2202 /* figure hash bucket */
2203 hash = _eet_hash_gen(name, ef->header->directory->size);
2205 data_size = comp ? 12 + ((size * 101) / 100) : size;
2207 if (comp || !cipher_key)
2209 data2 = malloc(data_size);
2214 /* if we want to compress */
2219 /* compress the data with max compression */
2220 buflen = (uLongf)data_size;
2221 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2222 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2228 /* record compressed chunk size */
2229 data_size = (int)buflen;
2230 if (data_size < 0 || data_size >= size)
2239 data3 = realloc(data2, data_size);
2247 void *data_ciphered = NULL;
2248 unsigned int data_ciphered_sz = 0;
2251 tmp = comp ? data2 : data;
2252 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2253 &data_ciphered, &data_ciphered_sz))
2258 data2 = data_ciphered;
2259 data_size = data_ciphered_sz;
2264 free(data_ciphered);
2271 memcpy(data2, data, size);
2273 /* Does this node already exist? */
2274 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2277 if ((efn->name) && (eet_string_match(efn->name, name)))
2281 efn->ciphered = cipher_key ? 1 : 0;
2282 efn->compression = !!comp;
2283 efn->size = data_size;
2284 efn->data_size = size;
2286 /* Put the offset above the limit to avoid direct access */
2287 efn->offset = ef->data_size + 1;
2292 if (!exists_already)
2294 efn = malloc(sizeof(Eet_File_Node));
2301 efn->name = strdup(name);
2302 efn->name_size = strlen(efn->name) + 1;
2305 efn->next = ef->header->directory->nodes[hash];
2306 ef->header->directory->nodes[hash] = efn;
2307 /* Put the offset above the limit to avoid direct access */
2308 efn->offset = ef->data_size + 1;
2310 efn->ciphered = cipher_key ? 1 : 0;
2311 efn->compression = !!comp;
2312 efn->size = data_size;
2313 efn->data_size = size;
2317 /* flags that writes are pending */
2318 ef->writes_pending = 1;
2325 } /* eet_write_cipher */
2328 eet_write(Eet_File *ef,
2334 return eet_write_cipher(ef, name, data, size, comp, NULL);
2338 eet_delete(Eet_File *ef,
2342 Eet_File_Node *pefn;
2344 int exists_already = 0;
2346 /* check to see its' an eet file pointer */
2347 if (eet_check_pointer(ef))
2353 /* deleting keys is only possible in RW or WRITE mode */
2354 if (ef->mode == EET_FILE_MODE_READ)
2357 if (eet_check_header(ef))
2362 /* figure hash bucket */
2363 hash = _eet_hash_gen(name, ef->header->directory->size);
2365 /* Does this node already exist? */
2366 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2368 pefn = efn, efn = efn->next)
2371 if (eet_string_match(efn->name, name))
2377 ef->header->directory->nodes[hash] = efn->next;
2379 pefn->next = efn->next;
2389 /* flags that writes are pending */
2391 ef->writes_pending = 1;
2395 /* update access time */
2396 return exists_already;
2399 EAPI Eet_Dictionary *
2400 eet_dictionary_get(Eet_File *ef)
2402 if (eet_check_pointer(ef))
2406 } /* eet_dictionary_get */
2409 eet_list(Eet_File *ef,
2414 char **list_ret = NULL;
2416 int list_count_alloc = 0;
2419 /* check to see its' an eet file pointer */
2420 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2422 ((ef->mode != EET_FILE_MODE_READ) &&
2423 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2431 if (!strcmp(glob, "*"))
2436 /* loop through all entries */
2437 num = (1 << ef->header->directory->size);
2438 for (i = 0; i < num; i++)
2440 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2442 /* if the entry matches the input glob
2443 * check for * explicitly, because on some systems, * isn't well
2446 if ((!glob) || !fnmatch(glob, efn->name, 0))
2448 /* add it to our list */
2451 /* only realloc in 32 entry chunks */
2452 if (list_count > list_count_alloc)
2454 char **new_list = NULL;
2456 list_count_alloc += 64;
2458 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2466 list_ret = new_list;
2469 /* put pointer of name string in */
2470 list_ret[list_count - 1] = efn->name;
2477 /* return count and list */
2479 *count_ret = list_count;
2493 eet_num_entries(Eet_File *ef)
2495 int i, num, ret = 0;
2498 /* check to see its' an eet file pointer */
2499 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2500 ((ef->mode != EET_FILE_MODE_READ) &&
2501 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2506 /* loop through all entries */
2507 num = (1 << ef->header->directory->size);
2508 for (i = 0; i < num; i++)
2510 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2517 } /* eet_num_entries */
2519 static Eet_File_Node *
2520 find_node_by_name(Eet_File *ef,
2526 /* get hash bucket this should be in */
2527 hash = _eet_hash_gen(name, ef->header->directory->size);
2529 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2531 if (eet_string_match(efn->name, name))
2536 } /* find_node_by_name */
2539 read_data_from_disk(Eet_File *ef,
2544 if (efn->offset > ef->data_size)
2550 if ((efn->offset + len) > ef->data_size)
2553 memcpy(buf, ef->data + efn->offset, len);
2556 } /* read_data_from_disk */