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_POSIX_THREADS
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_THREADS
113 # ifdef EFL_HAVE_POSIX_THREADS
114 pthread_mutex_t file_lock;
120 unsigned char writes_pending : 1;
121 unsigned char delete_me_now : 1;
124 struct _Eet_File_Header
127 Eet_File_Directory *directory;
130 struct _Eet_File_Directory
133 Eet_File_Node **nodes;
136 struct _Eet_File_Node
140 Eet_File_Node *next; /* FIXME: make buckets linked lists */
143 int dictionary_offset;
150 unsigned char free_name : 1;
151 unsigned char compression : 1;
152 unsigned char ciphered : 1;
153 unsigned char alias : 1;
158 /* NB: all int's are stored in network byte order on disk */
160 int magic; /* magic number ie 0x1ee7ff00 */
161 int num_directory_entries; /* number of directory entries to follow */
162 int bytes_directory_entries; /* bytes of directory entries to follow */
165 int offset; /* bytes offset into file for data chunk */
166 int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
167 int size; /* size of the data chunk */
168 int data_size; /* size of the (uncompressed) data chunk */
169 int name_size; /* length in bytes of the name field */
170 char name[name_size]; /* name string (variable length) and \0 terminated */
171 } directory[num_directory_entries];
172 /* and now startes the data stream... */
177 /* NB: all int's are stored in network byte order on disk */
179 int magic; /* magic number ie 0x1ee70f42 */
180 int num_directory_entries; /* number of directory entries to follow */
181 int num_dictionary_entries; /* number of dictionary entries to follow */
184 int data_offset; /* bytes offset into file for data chunk */
185 int size; /* size of the data chunk */
186 int data_size; /* size of the (uncompressed) data chunk */
187 int name_offset; /* bytes offset into file for name string */
188 int name_size; /* length in bytes of the name field */
189 int flags; /* bit flags - for now:
190 bit 0 => compresion on/off
191 bit 1 => ciphered on/off
194 } directory[num_directory_entries];
202 } dictionary[num_dictionary_entries];
203 /* now start the string stream. */
204 /* and right after them the data stream. */
205 int magic_sign; /* Optional, only if the eet file is signed. */
206 int signature_length; /* Signature length. */
207 int x509_length; /* Public certificate that signed the file. */
208 char signature[signature_length]; /* The signature. */
209 char x509[x509_length]; /* The public certificate. */
212 #define EET_FILE2_HEADER_COUNT 3
213 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
214 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
216 #define EET_FILE2_HEADER_SIZE (sizeof(int) * EET_FILE2_HEADER_COUNT)
217 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DIRECTORY_ENTRY_COUNT)
218 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DICTIONARY_ENTRY_COUNT)
220 /* prototypes of internal calls */
221 static Eet_File *eet_cache_find(const char *path, Eet_File **cache, int cache_num);
222 static void eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
223 static void eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
224 static int eet_string_match(const char *s1, const char *s2);
226 static Eet_Error eet_flush(Eet_File *ef);
228 static Eet_Error eet_flush2(Eet_File *ef);
229 static Eet_File_Node *find_node_by_name(Eet_File *ef, const char *name);
230 static int read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len);
232 static Eet_Error eet_internal_close(Eet_File *ef, Eina_Bool locked);
234 #ifdef EFL_HAVE_THREADS
236 # ifdef EFL_HAVE_POSIX_THREADS
238 static pthread_mutex_t eet_cache_lock = PTHREAD_MUTEX_INITIALIZER;
240 # define LOCK_CACHE pthread_mutex_lock(&eet_cache_lock)
241 # define UNLOCK_CACHE pthread_mutex_unlock(&eet_cache_lock)
243 # define INIT_FILE(File) pthread_mutex_init(&File->file_lock, NULL)
244 # define LOCK_FILE(File) pthread_mutex_lock(&File->file_lock)
245 # define UNLOCK_FILE(File) pthread_mutex_unlock(&File->file_lock)
246 # define DESTROY_FILE(File) pthread_mutex_destroy(&File->file_lock)
248 # else /* EFL_HAVE_WIN32_THREADS */
250 static HANDLE eet_cache_lock = NULL;
252 # define LOCK_CACHE WaitForSingleObject(eet_cache_lock, INFINITE)
253 # define UNLOCK_CACHE ReleaseMutex(eet_cache_lock)
255 # define INIT_FILE(File) File->file_lock = CreateMutex(NULL, FALSE, NULL)
256 # define LOCK_FILE(File) WaitForSingleObject(File->file_lock, INFINITE)
257 # define UNLOCK_FILE(File) ReleaseMutex(File->file_lock)
258 # define DESTROY_FILE(File) CloseHandle(File->file_lock)
260 # endif /* EFL_HAVE_WIN32_THREADS */
264 # define LOCK_CACHE do {} while (0)
265 # define UNLOCK_CACHE do {} while (0)
267 # define INIT_FILE(File) do {} while (0)
268 # define LOCK_FILE(File) do {} while (0)
269 # define UNLOCK_FILE(File) do {} while (0)
270 # define DESTROY_FILE(File) do {} while (0)
272 #endif /* EFL_HAVE_THREADS */
274 /* cache. i don't expect this to ever be large, so arrays will do */
275 static int eet_writers_num = 0;
276 static int eet_writers_alloc = 0;
277 static Eet_File **eet_writers = NULL;
278 static int eet_readers_num = 0;
279 static int eet_readers_alloc = 0;
280 static Eet_File **eet_readers = NULL;
281 static int eet_init_count = 0;
283 /* log domain variable */
284 int _eet_log_dom_global = -1;
286 /* Check to see its' an eet file pointer */
288 eet_check_pointer(const Eet_File *ef)
290 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
296 eet_check_header(const Eet_File *ef)
300 if (!ef->header->directory)
306 eet_test_close(int test, Eet_File *ef)
310 ef->delete_me_now = 1;
311 eet_internal_close(ef, EINA_TRUE);
316 /* find an eet file in the currently in use cache */
318 eet_cache_find(const char *path, Eet_File **cache, int cache_num)
323 for (i = 0; i < cache_num; i++)
325 /* if matches real path - return it */
326 if (eet_string_match(cache[i]->path, path))
328 if (!cache[i]->delete_me_now)
337 /* add to end of cache */
338 /* this should only be called when the cache lock is already held */
340 eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
342 Eet_File **new_cache;
346 new_cache_num = *cache_num;
347 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
349 Eet_File *del_ef = NULL;
353 for (i = 0; i < new_cache_num; i++)
355 if (new_cache[i]->references == 0)
357 del_ef = new_cache[i];
364 del_ef->delete_me_now = 1;
365 eet_internal_close(del_ef, EINA_TRUE);
370 new_cache_num = *cache_num;
371 new_cache_alloc = *cache_alloc;
373 if (new_cache_num > new_cache_alloc)
375 new_cache_alloc += 16;
376 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
379 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
383 new_cache[new_cache_num - 1] = ef;
385 *cache_num = new_cache_num;
386 *cache_alloc = new_cache_alloc;
389 /* delete from cache */
390 /* this should only be called when the cache lock is already held */
392 eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
394 Eet_File **new_cache;
395 int new_cache_num, new_cache_alloc;
399 new_cache_num = *cache_num;
400 new_cache_alloc = *cache_alloc;
401 if (new_cache_num <= 0)
404 for (i = 0; i < new_cache_num; i++)
406 if (new_cache[i] == ef)
410 if (i >= new_cache_num)
414 for (j = i; j < new_cache_num; j++)
415 new_cache[j] = new_cache[j + 1];
417 if (new_cache_num <= (new_cache_alloc - 16))
419 new_cache_alloc -= 16;
420 if (new_cache_num > 0)
422 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
425 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
436 *cache_num = new_cache_num;
437 *cache_alloc = new_cache_alloc;
440 /* internal string match. null friendly, catches same ptr */
442 eet_string_match(const char *s1, const char *s2)
444 /* both null- no match */
445 if ((!s1) || (!s2)) return 0;
446 if (s1 == s2) return 1;
447 return (!strcmp(s1, s2));
450 /* flush out writes to a v2 eet file */
452 eet_flush2(Eet_File *ef)
456 Eet_Error error = EET_ERROR_NONE;
457 int head[EET_FILE2_HEADER_COUNT];
458 int num_directory_entries = 0;
459 int num_dictionary_entries = 0;
460 int bytes_directory_entries = 0;
461 int bytes_dictionary_entries = 0;
462 int bytes_strings = 0;
464 int strings_offset = 0;
469 if (eet_check_pointer(ef))
470 return EET_ERROR_BAD_OBJECT;
471 if (eet_check_header(ef))
472 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, S_IRUSR | S_IWUSR);
484 fp = fdopen(fd, "wb");
485 if (!fp) return EET_ERROR_NOT_WRITABLE;
486 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
489 return EET_ERROR_NOT_WRITABLE;
491 /* calculate string base offset and data base offset */
492 num = (1 << ef->header->directory->size);
493 for (i = 0; i < num; ++i)
495 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
497 num_directory_entries++;
498 bytes_strings += strlen(efn->name) + 1;
503 num_dictionary_entries = ef->ed->count;
505 for (i = 0; i < num_dictionary_entries; ++i)
506 bytes_strings += ef->ed->all[i].len;
509 /* calculate section bytes size */
510 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
511 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
513 /* calculate per entry offset */
514 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
515 data_offset = bytes_directory_entries + bytes_dictionary_entries + bytes_strings;
517 for (i = 0; i < num; ++i)
519 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
521 efn->offset = data_offset;
522 data_offset += efn->size;
524 efn->name_offset = strings_offset;
525 strings_offset += efn->name_size;
529 /* calculate dictionary strings offset */
531 ef->ed->offset = strings_offset;
533 /* go thru and write the header */
534 head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE2);
535 head[1] = (int) htonl ((unsigned int) num_directory_entries);
536 head[2] = (int) htonl ((unsigned int) num_dictionary_entries);
538 fseek(fp, 0, SEEK_SET);
539 if (fwrite(head, sizeof (head), 1, fp) != 1)
542 /* write directories entry */
543 for (i = 0; i < num; i++)
545 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
548 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
550 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
552 ibuf[0] = (int) htonl ((unsigned int) efn->offset);
553 ibuf[1] = (int) htonl ((unsigned int) efn->size);
554 ibuf[2] = (int) htonl ((unsigned int) efn->data_size);
555 ibuf[3] = (int) htonl ((unsigned int) efn->name_offset);
556 ibuf[4] = (int) htonl ((unsigned int) efn->name_size);
557 ibuf[5] = (int) htonl ((unsigned int) flag);
559 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
564 /* write dictionnary */
567 int offset = strings_offset;
569 for (j = 0; j < ef->ed->count; ++j)
571 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
573 sbuf[0] = (int) htonl ((unsigned int) ef->ed->all[j].hash);
574 sbuf[1] = (int) htonl ((unsigned int) offset);
575 sbuf[2] = (int) htonl ((unsigned int) ef->ed->all[j].len);
576 sbuf[3] = (int) htonl ((unsigned int) ef->ed->all[j].prev);
577 sbuf[4] = (int) htonl ((unsigned int) ef->ed->all[j].next);
579 offset += ef->ed->all[j].len;
581 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
586 /* write directories name */
587 for (i = 0; i < num; i++)
589 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
591 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
599 for (j = 0; j < ef->ed->count; ++j)
601 if (ef->ed->all[j].str)
603 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
608 if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, fp) != 1)
615 for (i = 0; i < num; i++)
617 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
619 if (fwrite(efn->data, efn->size, 1, fp) != 1)
624 /* flush all write to the file. */
626 // this is going to really cause trouble. if ANYTHING this needs to go into a
627 // thread spawned off - but even then...
628 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
629 // manual pages at eachother, but ext4 broke behavior that has been in place
630 // for decades and that 1000's of apps rely on daily - that is that one operation
631 // to disk is committed to disk BEFORE following operations, so the fs retains
632 // a consistent state
633 // fsync(fileno(fp));
635 /* append signature if required */
638 error = eet_identity_sign(fp, ef->key);
639 if (error != EET_ERROR_NONE)
643 /* no more writes pending */
644 ef->writes_pending = 0;
648 return EET_ERROR_NONE;
655 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
656 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
657 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
658 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
659 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;
678 _eet_log_dom_global = eina_log_domain_register("Eet", EET_DEFAULT_LOG_COLOR);
679 if (_eet_log_dom_global < 0)
681 EINA_LOG_ERR("Eet Can not create a general log domain.");
685 if (!eet_node_init())
687 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
688 goto unregister_log_domain;
692 /* Before the library can be used, it must initialize itself if needed. */
693 if (gcry_control (GCRYCTL_ANY_INITIALIZATION_P) == 0)
695 gcry_check_version(NULL);
696 /* Disable warning messages about problems with the secure memory subsystem.
697 This command should be run right after gcry_check_version. */
698 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
700 /* This command is used to allocate a pool of secure memory and thus
701 enabling the use of secure memory. It also drops all extra privileges the
702 process has (i.e. if it is run as setuid (root)). If the argument nbytes
703 is 0, secure memory will be disabled. The minimum amount of secure memory
704 allocated is currently 16384 bytes; you may thus use a value of 1 to
705 request that default size. */
706 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
707 WRN("BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
709 if (gnutls_global_init())
713 ERR_load_crypto_strings();
714 OpenSSL_add_all_algorithms();
717 return eet_init_count;
721 unregister_log_domain:
722 eina_log_domain_unregister(_eet_log_dom_global);
723 _eet_log_dom_global = -1;
726 return --eet_init_count;
732 if (--eet_init_count != 0)
733 return eet_init_count;
738 gnutls_global_deinit();
744 eina_log_domain_unregister(_eet_log_dom_global);
745 _eet_log_dom_global = -1;
748 return eet_init_count;
752 eet_sync(Eet_File *ef)
756 if (eet_check_pointer(ef))
757 return EET_ERROR_BAD_OBJECT;
759 if ((ef->mode != EET_FILE_MODE_WRITE) &&
760 (ef->mode != EET_FILE_MODE_READ_WRITE))
761 return EET_ERROR_NOT_WRITABLE;
763 if (!ef->writes_pending)
764 return EET_ERROR_NONE;
768 ret = eet_flush2(ef);
781 * We need to compute the list of eet file to close separately from the cache,
782 * due to eet_close removing them from the cache after each call.
785 for (i = 0; i < eet_writers_num; i++)
787 if (eet_writers[i]->references <= 0) num++;
790 for (i = 0; i < eet_readers_num; i++)
792 if (eet_readers[i]->references <= 0) num++;
797 Eet_File **closelist = NULL;
799 closelist = alloca(num * sizeof(Eet_File *));
801 for (i = 0; i < eet_writers_num; i++)
803 if (eet_writers[i]->references <= 0)
805 closelist[num] = eet_writers[i];
806 eet_writers[i]->delete_me_now = 1;
811 for (i = 0; i < eet_readers_num; i++)
813 if (eet_readers[i]->references <= 0)
815 closelist[num] = eet_readers[i];
816 eet_readers[i]->delete_me_now = 1;
821 for (i = 0; i < num; i++)
823 eet_internal_close(closelist[i], EINA_TRUE);
829 /* FIXME: MMAP race condition in READ_WRITE_MODE */
831 eet_internal_read2(Eet_File *ef)
833 const int *data = (const int*) ef->data;
834 const char *start = (const char*) ef->data;
836 int num_directory_entries;
837 int bytes_directory_entries;
838 int num_dictionary_entries;
839 int bytes_dictionary_entries;
840 int signature_base_offset;
844 if (eet_test_close((int) ntohl(*data) != EET_MAGIC_FILE2, ef))
848 #define GET_INT(Value, Pointer, Index) \
850 Value = ntohl(*Pointer); \
852 Index += sizeof(int); \
855 /* get entries count and byte count */
856 GET_INT(num_directory_entries, data, idx);
857 /* get dictionary count and byte count */
858 GET_INT(num_dictionary_entries, data, idx);
860 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
861 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
863 /* we cant have <= 0 values here - invalid */
864 if (eet_test_close((num_directory_entries <= 0), ef))
867 /* we cant have more bytes directory and bytes in dictionaries than the size of the file */
868 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) > ef->data_size, ef))
871 /* allocate header */
872 ef->header = calloc(1, sizeof(Eet_File_Header));
873 if (eet_test_close(!ef->header, ef))
876 ef->header->magic = EET_MAGIC_FILE_HEADER;
878 /* allocate directory block in ram */
879 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
880 if (eet_test_close(!ef->header->directory, ef))
883 /* 8 bit hash table (256 buckets) */
884 ef->header->directory->size = 8;
885 /* allocate base hash table */
886 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
887 if (eet_test_close(!ef->header->directory->nodes, ef))
890 signature_base_offset = 0;
892 /* actually read the directory block - all of it, into ram */
893 for (i = 0; i < num_directory_entries; ++i)
902 /* out directory block is inconsistent - we have oveerun our */
903 /* dynamic block buffer before we finished scanning dir entries */
904 efn = malloc (sizeof(Eet_File_Node));
905 if (eet_test_close(!efn, ef))
908 /* get entrie header */
909 GET_INT(efn->offset, data, idx);
910 GET_INT(efn->size, data, idx);
911 GET_INT(efn->data_size, data, idx);
912 GET_INT(name_offset, data, idx);
913 GET_INT(name_size, data, idx);
914 GET_INT(flag, data, idx);
916 efn->compression = flag & 0x1 ? 1 : 0;
917 efn->ciphered = flag & 0x2 ? 1 : 0;
918 efn->alias = flag & 0x4 ? 1 : 0;
920 #define EFN_TEST(Test, Ef, Efn) \
921 if (eet_test_close(Test, Ef)) \
927 /* check data pointer position */
928 EFN_TEST(!((efn->size > 0)
929 && (efn->offset + efn->size <= ef->data_size)
930 && (efn->offset > bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
932 /* check name position */
933 EFN_TEST(!((name_size > 0)
934 && (name_offset + name_size < ef->data_size)
935 && (name_offset >= bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
937 name = start + name_offset;
939 /* check '\0' at the end of name string */
940 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
943 efn->name = (char*) name;
944 efn->name_size = name_size;
946 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
947 efn->next = ef->header->directory->nodes[hash];
948 ef->header->directory->nodes[hash] = efn;
950 /* read-only mode, so currently we have no data loaded */
951 if (ef->mode == EET_FILE_MODE_READ)
953 /* read-write mode - read everything into ram */
956 efn->data = malloc(efn->size);
958 memcpy(efn->data, ef->data + efn->offset, efn->size);
961 /* compute the possible position of a signature */
962 if (signature_base_offset < efn->offset + efn->size)
963 signature_base_offset = efn->offset + efn->size;
968 if (num_dictionary_entries)
970 const int *dico = (const int*) ef->data + EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries + EET_FILE2_HEADER_COUNT;
973 if (eet_test_close((num_dictionary_entries * (int) EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) > (bytes_dictionary_entries + bytes_directory_entries), ef))
976 ef->ed = calloc(1, sizeof (Eet_Dictionary));
977 if (eet_test_close(!ef->ed, ef)) return NULL;
979 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
980 if (eet_test_close(!ef->ed->all, ef)) return NULL;
982 ef->ed->count = num_dictionary_entries;
983 ef->ed->total = num_dictionary_entries;
984 ef->ed->start = start + bytes_dictionary_entries + bytes_directory_entries;
985 ef->ed->end = ef->ed->start;
987 for (j = 0; j < ef->ed->count; ++j)
992 GET_INT(hash, dico, idx);
993 GET_INT(offset, dico, idx);
994 GET_INT(ef->ed->all[j].len, dico, idx);
995 GET_INT(ef->ed->all[j].prev, dico, idx);
996 GET_INT(ef->ed->all[j].next, dico, idx);
998 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
999 So stick to int and check the value. */
1000 if (eet_test_close(hash & 0xFFFFFF00, ef)) return NULL;
1002 /* Check string position */
1003 if (eet_test_close(!((ef->ed->all[j].len > 0)
1004 && (offset > (bytes_dictionary_entries + bytes_directory_entries))
1005 && (offset + ef->ed->all[j].len < ef->data_size)), ef))
1008 ef->ed->all[j].mmap = start + offset;
1009 ef->ed->all[j].str = NULL;
1011 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
1012 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
1014 /* Check '\0' at the end of the string */
1015 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] != '\0', ef)) return NULL;
1017 ef->ed->all[j].hash = hash;
1018 if (ef->ed->all[j].prev == -1)
1019 ef->ed->hash[hash] = j;
1021 /* compute the possible position of a signature */
1022 if (signature_base_offset < offset + ef->ed->all[j].len)
1023 signature_base_offset = offset + ef->ed->all[j].len;
1027 /* Check if the file is signed */
1028 ef->x509_der = NULL;
1029 ef->x509_length = 0;
1030 ef->signature = NULL;
1031 ef->signature_length = 0;
1033 if (signature_base_offset < ef->data_size)
1035 #ifdef HAVE_SIGNATURE
1036 const unsigned char *buffer = ((const unsigned char*) ef->data) + signature_base_offset;
1037 ef->x509_der = eet_identity_check(ef->data, signature_base_offset,
1038 &ef->sha1, &ef->sha1_length,
1039 buffer, ef->data_size - signature_base_offset,
1040 &ef->signature, &ef->signature_length,
1043 if (eet_test_close(ef->x509_der == NULL, ef)) return NULL;
1045 ERR("This file could be signed but you didn't compile the necessary code to check the signature.");
1052 #if EET_OLD_EET_FILE_FORMAT
1054 eet_internal_read1(Eet_File *ef)
1056 const unsigned char *dyn_buf = NULL;
1057 const unsigned char *p = NULL;
1063 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);
1065 /* build header table if read mode */
1068 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1071 #define EXTRACT_INT(Value, Pointer, Index) \
1074 memcpy(&tmp, Pointer + Index, sizeof(int)); \
1075 Value = ntohl(tmp); \
1076 Index += sizeof(int); \
1079 /* get entries count and byte count */
1080 EXTRACT_INT(num_entries, ef->data, idx);
1081 EXTRACT_INT(byte_entries, ef->data, idx);
1083 /* we cant have <= 0 values here - invalid */
1084 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1087 /* we can't have more entires than minimum bytes for those! invalid! */
1088 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1091 /* check we will not outrun the file limit */
1092 if (eet_test_close(((byte_entries + (int) sizeof(int) * 3) > ef->data_size), ef))
1095 /* allocate header */
1096 ef->header = calloc(1, sizeof(Eet_File_Header));
1097 if (eet_test_close(!ef->header, ef))
1100 ef->header->magic = EET_MAGIC_FILE_HEADER;
1102 /* allocate directory block in ram */
1103 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1104 if (eet_test_close(!ef->header->directory, ef))
1107 /* 8 bit hash table (256 buckets) */
1108 ef->header->directory->size = 8;
1109 /* allocate base hash table */
1110 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1111 if (eet_test_close(!ef->header->directory->nodes, ef))
1114 /* actually read the directory block - all of it, into ram */
1115 dyn_buf = ef->data + idx;
1117 /* parse directory block */
1120 for (i = 0; i < num_entries; i++)
1129 #define HEADER_SIZE (sizeof(int) * 5)
1131 /* out directory block is inconsistent - we have oveerun our */
1132 /* dynamic block buffer before we finished scanning dir entries */
1133 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1136 /* allocate all the ram needed for this stored node accounting */
1137 efn = malloc (sizeof(Eet_File_Node));
1138 if (eet_test_close(!efn, ef))
1141 /* get entrie header */
1142 EXTRACT_INT(efn->offset, p, indexn);
1143 EXTRACT_INT(efn->compression, p, indexn);
1144 EXTRACT_INT(efn->size, p, indexn);
1145 EXTRACT_INT(efn->data_size, p, indexn);
1146 EXTRACT_INT(name_size, p, indexn);
1148 efn->name_size = name_size;
1153 if (eet_test_close(efn->size <= 0, ef))
1159 /* invalid name_size */
1160 if (eet_test_close(name_size <= 0, ef))
1166 /* reading name would mean falling off end of dyn_buf - invalid */
1167 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1173 /* This code is useless if we dont want backward compatibility */
1174 for (k = name_size; k > 0 && ((unsigned char) * (p + HEADER_SIZE + k)) != 0; --k)
1177 efn->free_name = ((unsigned char) * (p + HEADER_SIZE + k)) != 0;
1181 efn->name = malloc(sizeof(char) * name_size + 1);
1182 if (eet_test_close(efn->name == NULL, ef))
1188 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1189 efn->name[name_size] = 0;
1191 WRN("File: %s is not up to date for key \"%s\" - needs rebuilding sometime", ef->path, efn->name);
1194 /* The only really usefull peace of code for efn->name (no backward compatibility) */
1195 efn->name = (char*)((unsigned char*)(p + HEADER_SIZE));
1197 /* get hash bucket it should go in */
1198 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1199 efn->next = ef->header->directory->nodes[hash];
1200 ef->header->directory->nodes[hash] = efn;
1202 /* read-only mode, so currently we have no data loaded */
1203 if (ef->mode == EET_FILE_MODE_READ)
1205 /* read-write mode - read everything into ram */
1208 data = malloc(efn->size);
1210 memcpy(data, ef->data + efn->offset, efn->size);
1214 p += HEADER_SIZE + name_size;
1221 * this should only be called when the cache lock is already held
1222 * (We could drop this restriction if we add a parameter to eet_test_close
1223 * that indicates if the lock is held or not. For now it is easiest
1224 * to just require that it is always held.)
1227 eet_internal_read(Eet_File *ef)
1229 const int *data = (const int*) ef->data;
1231 if (eet_test_close((ef->data == (void *)-1) || (ef->data == NULL), ef))
1234 if (eet_test_close(ef->data_size < (int) sizeof(int) * 3, ef))
1237 switch (ntohl(*data))
1239 #if EET_OLD_EET_FILE_FORMAT
1240 case EET_MAGIC_FILE:
1241 return eet_internal_read1(ef);
1243 case EET_MAGIC_FILE2:
1244 return eet_internal_read2(ef);
1246 ef->delete_me_now = 1;
1247 eet_internal_close(ef, EINA_TRUE);
1255 eet_internal_close(Eet_File *ef, Eina_Bool locked)
1259 /* check to see its' an eet file pointer */
1260 if (eet_check_pointer(ef))
1261 return EET_ERROR_BAD_OBJECT;
1263 if (!locked) LOCK_CACHE;
1267 /* if its still referenced - dont go any further */
1268 if (ef->references > 0) goto on_error;
1269 /* flush any writes */
1270 err = eet_flush2(ef);
1272 eet_identity_unref(ef->key);
1275 /* if not urgent to delete it - dont free it - leave it in cache */
1276 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1279 /* remove from cache */
1280 if (ef->mode == EET_FILE_MODE_READ)
1281 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1282 else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1283 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1285 /* we can unlock the cache now */
1286 if (!locked) UNLOCK_CACHE;
1293 if (ef->header->directory)
1295 if (ef->header->directory->nodes)
1299 num = (1 << ef->header->directory->size);
1300 for (i = 0; i < num; i++)
1304 while ((efn = ef->header->directory->nodes[i]))
1309 ef->header->directory->nodes[i] = efn->next;
1317 free(ef->header->directory->nodes);
1319 free(ef->header->directory);
1324 eet_dictionary_free(ef->ed);
1326 if (ef->sha1) free(ef->sha1);
1327 if (ef->data) munmap((void*)ef->data, ef->data_size);
1328 if (ef->readfp) fclose(ef->readfp);
1330 /* zero out ram for struct - caution tactic against stale memory use */
1331 memset(ef, 0, sizeof(Eet_File));
1338 if (!locked) UNLOCK_CACHE;
1339 return EET_ERROR_NONE;
1343 eet_memopen_read(const void *data, size_t size)
1347 if (data == NULL || size == 0)
1350 ef = malloc (sizeof (Eet_File));
1358 ef->magic = EET_MAGIC_FILE;
1360 ef->mode = EET_FILE_MODE_READ;
1363 ef->delete_me_now = 1;
1366 ef->data_size = size;
1368 ef->sha1_length = 0;
1370 /* eet_internal_read expects the cache lock to be held when it is called */
1372 ef = eet_internal_read(ef);
1378 eet_open(const char *file, Eet_File_Mode mode)
1383 struct stat file_stat;
1388 /* find the current file handle in cache*/
1391 if (mode == EET_FILE_MODE_READ)
1393 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1398 ef->delete_me_now = 1;
1399 eet_internal_close(ef, EINA_TRUE);
1401 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1403 else if ((mode == EET_FILE_MODE_WRITE) ||
1404 (mode == EET_FILE_MODE_READ_WRITE))
1406 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1409 ef->delete_me_now = 1;
1411 eet_internal_close(ef, EINA_TRUE);
1413 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1416 /* try open the file based on mode */
1417 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1419 /* Prevent garbage in futur comparison. */
1420 file_stat.st_mtime = 0;
1422 fp = fopen(file, "rb");
1423 if (!fp) goto open_error;
1424 if (fstat(fileno(fp), &file_stat))
1430 if ((mode == EET_FILE_MODE_READ) &&
1431 (file_stat.st_size < ((int) sizeof(int) * 3)))
1439 if (fp == NULL && mode == EET_FILE_MODE_READ) goto on_error;
1443 if (mode != EET_FILE_MODE_WRITE) return NULL;
1444 memset(&file_stat, 0, sizeof(file_stat));
1450 if (ef && (file_stat.st_mtime != ef->mtime))
1452 ef->delete_me_now = 1;
1454 eet_internal_close(ef, EINA_TRUE);
1460 /* reference it up and return it */
1461 if (fp != NULL) fclose(fp);
1467 file_len = strlen(file) + 1;
1469 /* Allocate struct for eet file and have it zero'd out */
1470 ef = malloc(sizeof(Eet_File) + file_len);
1474 /* fill some of the members */
1478 ef->path = ((char *)ef) + sizeof(Eet_File);
1479 memcpy(ef->path, file, file_len);
1480 ef->magic = EET_MAGIC_FILE;
1484 ef->mtime = file_stat.st_mtime;
1485 ef->writes_pending = 0;
1486 ef->delete_me_now = 0;
1490 ef->sha1_length = 0;
1492 ef->ed = (mode == EET_FILE_MODE_WRITE)
1493 || (ef->readfp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
1494 eet_dictionary_add() : NULL;
1496 if (ef->readfp == NULL &&
1497 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1500 /* if we can't open - bail out */
1501 if (eet_test_close(!ef->readfp, ef))
1504 fcntl(fileno(ef->readfp), F_SETFD, FD_CLOEXEC);
1505 /* if we opened for read or read-write */
1506 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1508 ef->data_size = file_stat.st_size;
1509 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1510 MAP_SHARED, fileno(ef->readfp), 0);
1511 if (eet_test_close((ef->data == MAP_FAILED), ef))
1513 ef = eet_internal_read(ef);
1520 if (ef->references == 1)
1522 if (ef->mode == EET_FILE_MODE_READ)
1523 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1525 if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1526 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1538 eet_mode_get(Eet_File *ef)
1540 /* check to see its' an eet file pointer */
1541 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1542 return EET_FILE_MODE_INVALID;
1548 eet_identity_x509(Eet_File *ef, int *der_length)
1550 if (!ef->x509_der) return NULL;
1552 if (der_length) *der_length = ef->x509_length;
1553 return ef->x509_der;
1557 eet_identity_signature(Eet_File *ef, int *signature_length)
1559 if (!ef->signature) return NULL;
1561 if (signature_length) *signature_length = ef->signature_length;
1562 return ef->signature;
1566 eet_identity_sha1(Eet_File *ef, int *sha1_length)
1569 ef->sha1 = eet_identity_compute_sha1(ef->data, ef->data_size, &ef->sha1_length);
1571 if (sha1_length) *sha1_length = ef->sha1_length;
1576 eet_identity_set(Eet_File *ef, Eet_Key *key)
1578 Eet_Key *tmp = ef->key;
1580 if (!ef) return EET_ERROR_BAD_OBJECT;
1583 eet_identity_ref(ef->key);
1584 eet_identity_unref(tmp);
1586 /* flags that writes are pending */
1587 ef->writes_pending = 1;
1589 return EET_ERROR_NONE;
1593 eet_close(Eet_File *ef)
1595 return eet_internal_close(ef, EINA_FALSE);
1599 eet_read_cipher(Eet_File *ef, const char *name, int *size_ret, const char *cipher_key)
1608 /* check to see its' an eet file pointer */
1609 if (eet_check_pointer(ef))
1613 if ((ef->mode != EET_FILE_MODE_READ) &&
1614 (ef->mode != EET_FILE_MODE_READ_WRITE))
1617 /* no header, return NULL */
1618 if (eet_check_header(ef))
1623 /* hunt hash bucket */
1624 efn = find_node_by_name(ef, name);
1625 if (!efn) goto on_error;
1627 /* get size (uncompressed, if compressed at all) */
1628 size = efn->data_size;
1631 data = malloc(size);
1632 if (!data) goto on_error;
1634 /* uncompressed data */
1635 if (efn->compression == 0)
1637 void *data_deciphered = NULL;
1638 unsigned int data_deciphered_sz = 0;
1639 /* if we alreayd have the data in ram... copy that */
1642 memcpy(data, efn->data, efn->size);
1644 if (!read_data_from_disk(ef, efn, data, size))
1646 if (efn->ciphered && cipher_key)
1648 if (eet_decipher(data, size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
1650 if (data_deciphered) free(data_deciphered);
1654 data = data_deciphered;
1655 size = data_deciphered_sz;
1658 /* compressed data */
1662 void *data_deciphered = NULL;
1663 unsigned int data_deciphered_sz = 0;
1665 int compr_size = efn->size;
1668 /* if we already have the data in ram... copy that */
1670 tmp_data = efn->data;
1673 tmp_data = malloc(compr_size);
1679 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1686 if (efn->ciphered && cipher_key)
1688 if (eet_decipher(tmp_data, compr_size, cipher_key, strlen(cipher_key), &data_deciphered, &data_deciphered_sz))
1690 if (free_tmp) free(tmp_data);
1691 if (data_deciphered) free(data_deciphered);
1695 tmp_data = data_deciphered;
1696 compr_size = data_deciphered_sz;
1701 if (uncompress((Bytef *)data, &dlen,
1702 tmp_data, (uLongf)compr_size))
1716 if (data[size - 1] != '\0')
1719 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1726 /* fill in return values */
1739 eet_read(Eet_File *ef, const char *name, int *size_ret)
1741 return eet_read_cipher(ef, name, size_ret, NULL);
1745 eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
1748 const char *data = NULL;
1754 /* check to see its' an eet file pointer */
1755 if (eet_check_pointer(ef))
1759 if ((ef->mode != EET_FILE_MODE_READ) &&
1760 (ef->mode != EET_FILE_MODE_READ_WRITE))
1763 /* no header, return NULL */
1764 if (eet_check_header(ef))
1769 /* hunt hash bucket */
1770 efn = find_node_by_name(ef, name);
1771 if (!efn) goto on_error;
1773 if (efn->offset < 0 && efn->data == NULL)
1776 /* get size (uncompressed, if compressed at all) */
1777 size = efn->data_size;
1781 data = efn->data ? efn->data : ef->data + efn->offset;
1783 /* handle alias case */
1784 if (efn->compression)
1787 int compr_size = efn->size;
1790 tmp = alloca(sizeof (compr_size));
1793 if (uncompress((Bytef *)tmp, &dlen, (Bytef *) data, (uLongf)compr_size))
1796 if (tmp[compr_size - 1] != '\0')
1799 return eet_read_direct(ef, tmp, size_ret);
1802 if (!data) goto on_error;
1803 if (data[size - 1] != '\0') goto on_error;
1805 return eet_read_direct(ef, data, size_ret);
1808 /* uncompressed data */
1809 if (efn->compression == 0
1810 && efn->ciphered == 0)
1811 data = efn->data ? efn->data : ef->data + efn->offset;
1812 /* compressed data */
1816 /* fill in return values */
1830 eet_alias(Eet_File *ef, const char *name, const char *destination, int comp)
1834 Eina_Bool exists_already = EINA_FALSE;
1838 /* check to see its' an eet file pointer */
1839 if (eet_check_pointer(ef))
1841 if ((!name) || (!destination))
1843 if ((ef->mode != EET_FILE_MODE_WRITE) &&
1844 (ef->mode != EET_FILE_MODE_READ_WRITE))
1851 /* allocate header */
1852 ef->header = calloc(1, sizeof(Eet_File_Header));
1856 ef->header->magic = EET_MAGIC_FILE_HEADER;
1857 /* allocate directory block in ram */
1858 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1859 if (!ef->header->directory)
1866 /* 8 bit hash table (256 buckets) */
1867 ef->header->directory->size = 8;
1868 /* allocate base hash table */
1869 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1870 if (!ef->header->directory->nodes)
1872 free(ef->header->directory);
1878 /* figure hash bucket */
1879 hash = _eet_hash_gen(name, ef->header->directory->size);
1882 12 + (((strlen(destination) + 1) * 101) / 100)
1883 : strlen(destination) + 1;
1885 data2 = malloc(data_size);
1886 if (!data2) goto on_error;
1888 /* if we want to compress */
1893 /* compress the data with max compression */
1894 buflen = (uLongf)data_size;
1895 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
1896 (uLong)strlen(destination) + 1, Z_BEST_COMPRESSION) != Z_OK)
1901 /* record compressed chunk size */
1902 data_size = (int)buflen;
1903 if (data_size < 0 || data_size >= (int) (strlen(destination) + 1))
1906 data_size = strlen(destination) + 1;
1912 data3 = realloc(data2, data_size);
1919 memcpy(data2, destination, data_size);
1921 /* Does this node already exist? */
1922 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
1925 if ((efn->name) && (eet_string_match(efn->name, name)))
1930 efn->compression = !!comp;
1931 efn->size = data_size;
1932 efn->data_size = strlen(destination) + 1;
1935 exists_already = EINA_TRUE;
1939 if (!exists_already)
1941 efn = malloc(sizeof(Eet_File_Node));
1947 efn->name = strdup(name);
1948 efn->name_size = strlen(efn->name) + 1;
1951 efn->next = ef->header->directory->nodes[hash];
1952 ef->header->directory->nodes[hash] = efn;
1956 efn->compression = !!comp;
1957 efn->size = data_size;
1958 efn->data_size = strlen(destination) + 1;
1962 /* flags that writes are pending */
1963 ef->writes_pending = 1;
1974 eet_write_cipher(Eet_File *ef, const char *name, const void *data, int size, int comp, const char *cipher_key)
1978 int exists_already = 0;
1982 /* check to see its' an eet file pointer */
1983 if (eet_check_pointer(ef))
1985 if ((!name) || (!data) || (size <= 0))
1987 if ((ef->mode != EET_FILE_MODE_WRITE) &&
1988 (ef->mode != EET_FILE_MODE_READ_WRITE))
1995 /* allocate header */
1996 ef->header = calloc(1, sizeof(Eet_File_Header));
2000 ef->header->magic = EET_MAGIC_FILE_HEADER;
2001 /* allocate directory block in ram */
2002 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2003 if (!ef->header->directory)
2010 /* 8 bit hash table (256 buckets) */
2011 ef->header->directory->size = 8;
2012 /* allocate base hash table */
2013 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
2014 if (!ef->header->directory->nodes)
2016 free(ef->header->directory);
2022 /* figure hash bucket */
2023 hash = _eet_hash_gen(name, ef->header->directory->size);
2025 data_size = comp ? 12 + ((size * 101) / 100) : size;
2027 if (comp || !cipher_key)
2029 data2 = malloc(data_size);
2030 if (!data2) goto on_error;
2033 /* if we want to compress */
2038 /* compress the data with max compression */
2039 buflen = (uLongf)data_size;
2040 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2041 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2046 /* record compressed chunk size */
2047 data_size = (int)buflen;
2048 if (data_size < 0 || data_size >= size)
2057 data3 = realloc(data2, data_size);
2065 void *data_ciphered = NULL;
2066 unsigned int data_ciphered_sz = 0;
2069 tmp = data2 ? data2 : data;
2070 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key), &data_ciphered, &data_ciphered_sz))
2072 if (data2) free(data2);
2073 data2 = data_ciphered;
2074 data_size = data_ciphered_sz;
2075 size = (data_size > size) ? data_size : size;
2079 if (data_ciphered) free(data_ciphered);
2085 memcpy(data2, data, size);
2087 /* Does this node already exist? */
2088 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2091 if ((efn->name) && (eet_string_match(efn->name, name)))
2095 efn->ciphered = cipher_key ? 1 : 0;
2096 efn->compression = !!comp;
2097 efn->size = data_size;
2098 efn->data_size = size;
2105 if (!exists_already)
2107 efn = malloc(sizeof(Eet_File_Node));
2113 efn->name = strdup(name);
2114 efn->name_size = strlen(efn->name) + 1;
2117 efn->next = ef->header->directory->nodes[hash];
2118 ef->header->directory->nodes[hash] = efn;
2121 efn->ciphered = cipher_key ? 1 : 0;
2122 efn->compression = !!comp;
2123 efn->size = data_size;
2124 efn->data_size = size;
2128 /* flags that writes are pending */
2129 ef->writes_pending = 1;
2139 eet_write(Eet_File *ef, const char *name, const void *data, int size, int comp)
2141 return eet_write_cipher(ef, name, data, size, comp, NULL);
2145 eet_delete(Eet_File *ef, const char *name)
2148 Eet_File_Node *pefn;
2150 int exists_already = 0;
2152 /* check to see its' an eet file pointer */
2153 if (eet_check_pointer(ef))
2158 /* deleting keys is only possible in RW or WRITE mode */
2159 if (ef->mode == EET_FILE_MODE_READ)
2162 if (eet_check_header(ef))
2167 /* figure hash bucket */
2168 hash = _eet_hash_gen(name, ef->header->directory->size);
2170 /* Does this node already exist? */
2171 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2173 pefn = efn, efn = efn->next)
2176 if (eet_string_match(efn->name, name))
2182 ef->header->directory->nodes[hash] = efn->next;
2184 pefn->next = efn->next;
2186 if (efn->free_name) free(efn->name);
2192 /* flags that writes are pending */
2194 ef->writes_pending = 1;
2198 /* update access time */
2199 return exists_already;
2202 EAPI Eet_Dictionary *
2203 eet_dictionary_get(Eet_File *ef)
2205 if (eet_check_pointer(ef)) return NULL;
2212 eet_list(Eet_File *ef, const char *glob, int *count_ret)
2215 char **list_ret = NULL;
2217 int list_count_alloc = 0;
2220 /* check to see its' an eet file pointer */
2221 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2223 ((ef->mode != EET_FILE_MODE_READ) &&
2224 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2232 if (!strcmp(glob, "*")) glob = NULL;
2236 /* loop through all entries */
2237 num = (1 << ef->header->directory->size);
2238 for (i = 0; i < num; i++)
2240 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2242 /* if the entry matches the input glob
2243 * check for * explicitly, because on some systems, * isn't well
2246 if ((!glob) || !fnmatch(glob, efn->name, 0))
2248 /* add it to our list */
2251 /* only realloc in 32 entry chunks */
2252 if (list_count > list_count_alloc)
2254 char **new_list = NULL;
2256 list_count_alloc += 64;
2257 new_list = realloc(list_ret, list_count_alloc * (sizeof(char *)));
2264 list_ret = new_list;
2267 /* put pointer of name string in */
2268 list_ret[list_count - 1] = efn->name;
2275 /* return count and list */
2277 *count_ret = list_count;
2291 eet_num_entries(Eet_File *ef)
2293 int i, num, ret = 0;
2296 /* check to see its' an eet file pointer */
2297 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2298 ((ef->mode != EET_FILE_MODE_READ) &&
2299 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2304 /* loop through all entries */
2305 num = (1 << ef->header->directory->size);
2306 for (i = 0; i < num; i++)
2308 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2317 static Eet_File_Node *
2318 find_node_by_name(Eet_File *ef, const char *name)
2323 /* get hash bucket this should be in */
2324 hash = _eet_hash_gen(name, ef->header->directory->size);
2326 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2328 if (eet_string_match(efn->name, name))
2336 read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len)
2338 if (efn->offset < 0) return 0;
2342 if ((efn->offset + len) > ef->data_size) return 0;
2343 memcpy(buf, ef->data + efn->offset, len);
2350 /* seek to data location */
2351 if (fseek(ef->readfp, efn->offset, SEEK_SET) < 0)
2355 len = fread(buf, len, 1, ef->readfp);