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"
70 static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
71 EAPI Eet_Version *eet_version = &_version;
75 #endif /* ifdef HAVE_REALPATH */
77 #define EET_MAGIC_FILE 0x1ee7ff00
78 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
80 #define EET_MAGIC_FILE2 0x1ee70f42
82 typedef struct _Eet_File_Header Eet_File_Header;
83 typedef struct _Eet_File_Node Eet_File_Node;
84 typedef struct _Eet_File_Directory Eet_File_Directory;
90 Eet_File_Header *header;
93 const unsigned char *data;
95 const void *signature;
103 unsigned long int data_size;
105 unsigned int signature_length;
110 unsigned char writes_pending : 1;
111 unsigned char delete_me_now : 1;
114 struct _Eet_File_Header
117 Eet_File_Directory *directory;
120 struct _Eet_File_Directory
123 Eet_File_Node **nodes;
126 struct _Eet_File_Node
130 Eet_File_Node *next; /* FIXME: make buckets linked lists */
132 unsigned long int offset;
133 unsigned long int dictionary_offset;
134 unsigned long int name_offset;
136 unsigned int name_size;
138 unsigned int data_size;
140 unsigned char free_name : 1;
141 unsigned char compression : 1;
142 unsigned char ciphered : 1;
143 unsigned char alias : 1;
148 /* NB: all int's are stored in network byte order on disk */
150 int magic; /* magic number ie 0x1ee7ff00 */
151 int num_directory_entries; /* number of directory entries to follow */
152 int bytes_directory_entries; /* bytes of directory entries to follow */
155 int offset; /* bytes offset into file for data chunk */
156 int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
157 int size; /* size of the data chunk */
158 int data_size; /* size of the (uncompressed) data chunk */
159 int name_size; /* length in bytes of the name field */
160 char name[name_size]; /* name string (variable length) and \0 terminated */
161 } directory[num_directory_entries];
162 /* and now startes the data stream... */
167 /* NB: all int's are stored in network byte order on disk */
169 int magic; /* magic number ie 0x1ee70f42 */
170 int num_directory_entries; /* number of directory entries to follow */
171 int num_dictionary_entries; /* number of dictionary entries to follow */
174 int data_offset; /* bytes offset into file for data chunk */
175 int size; /* size of the data chunk */
176 int data_size; /* size of the (uncompressed) data chunk */
177 int name_offset; /* bytes offset into file for name string */
178 int name_size; /* length in bytes of the name field */
179 int flags; /* bit flags - for now:
180 bit 0 => compresion on/off
181 bit 1 => ciphered on/off
184 } directory[num_directory_entries];
192 } dictionary[num_dictionary_entries];
193 /* now start the string stream. */
194 /* and right after them the data stream. */
195 int magic_sign; /* Optional, only if the eet file is signed. */
196 int signature_length; /* Signature length. */
197 int x509_length; /* Public certificate that signed the file. */
198 char signature[signature_length]; /* The signature. */
199 char x509[x509_length]; /* The public certificate. */
202 #define EET_FILE2_HEADER_COUNT 3
203 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
204 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
206 #define EET_FILE2_HEADER_SIZE (sizeof(int) *\
207 EET_FILE2_HEADER_COUNT)
208 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) *\
209 EET_FILE2_DIRECTORY_ENTRY_COUNT)
210 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) *\
211 EET_FILE2_DICTIONARY_ENTRY_COUNT)
213 /* prototypes of internal calls */
214 static Eet_File * eet_cache_find(const char *path,
217 static void eet_cache_add(Eet_File *ef,
221 static void eet_cache_del(Eet_File *ef,
225 static int eet_string_match(const char *s1, const char *s2);
227 static Eet_Error eet_flush(Eet_File *ef);
229 static Eet_Error eet_flush2(Eet_File *ef);
230 static Eet_File_Node * find_node_by_name(Eet_File *ef, const char *name);
231 static int read_data_from_disk(Eet_File *ef,
236 static Eet_Error eet_internal_close(Eet_File *ef, Eina_Bool locked);
238 static Eina_Lock eet_cache_lock;
240 #define LOCK_CACHE eina_lock_take(&eet_cache_lock)
241 #define UNLOCK_CACHE eina_lock_release(&eet_cache_lock)
243 #define INIT_FILE(File) eina_lock_new(&File->file_lock)
244 #define LOCK_FILE(File) eina_lock_take(&File->file_lock)
245 #define UNLOCK_FILE(File) eina_lock_release(&File->file_lock)
246 #define DESTROY_FILE(File) eina_lock_free(&File->file_lock)
248 /* cache. i don't expect this to ever be large, so arrays will do */
249 static int eet_writers_num = 0;
250 static int eet_writers_alloc = 0;
251 static Eet_File **eet_writers = NULL;
252 static int eet_readers_num = 0;
253 static int eet_readers_alloc = 0;
254 static Eet_File **eet_readers = NULL;
255 static int eet_init_count = 0;
257 /* log domain variable */
258 int _eet_log_dom_global = -1;
260 /* Check to see its' an eet file pointer */
262 eet_check_pointer(const Eet_File *ef)
264 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
268 } /* eet_check_pointer */
271 eet_check_header(const Eet_File *ef)
276 if (!ef->header->directory)
280 } /* eet_check_header */
283 eet_test_close(int test,
288 ef->delete_me_now = 1;
289 eet_internal_close(ef, EINA_TRUE);
293 } /* eet_test_close */
295 /* find an eet file in the currently in use cache */
297 eet_cache_find(const char *path,
304 for (i = 0; i < cache_num; i++)
306 /* if matches real path - return it */
307 if (eet_string_match(cache[i]->path, path))
308 if (!cache[i]->delete_me_now)
315 } /* eet_cache_find */
317 /* add to end of cache */
318 /* this should only be called when the cache lock is already held */
320 eet_cache_add(Eet_File *ef,
325 Eet_File **new_cache;
329 new_cache_num = *cache_num;
330 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
332 Eet_File *del_ef = NULL;
336 for (i = 0; i < new_cache_num; i++)
338 if (new_cache[i]->references == 0)
340 del_ef = new_cache[i];
347 del_ef->delete_me_now = 1;
348 eet_internal_close(del_ef, EINA_TRUE);
353 new_cache_num = *cache_num;
354 new_cache_alloc = *cache_alloc;
356 if (new_cache_num > new_cache_alloc)
358 new_cache_alloc += 16;
359 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
362 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
367 new_cache[new_cache_num - 1] = ef;
369 *cache_num = new_cache_num;
370 *cache_alloc = new_cache_alloc;
371 } /* eet_cache_add */
373 /* delete from cache */
374 /* this should only be called when the cache lock is already held */
376 eet_cache_del(Eet_File *ef,
381 Eet_File **new_cache;
382 int new_cache_num, new_cache_alloc;
386 new_cache_num = *cache_num;
387 new_cache_alloc = *cache_alloc;
388 if (new_cache_num <= 0)
391 for (i = 0; i < new_cache_num; i++)
393 if (new_cache[i] == ef)
397 if (i >= new_cache_num)
401 for (j = i; j < new_cache_num; j++)
402 new_cache[j] = new_cache[j + 1];
404 if (new_cache_num <= (new_cache_alloc - 16))
406 new_cache_alloc -= 16;
407 if (new_cache_num > 0)
409 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
412 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
424 *cache_num = new_cache_num;
425 *cache_alloc = new_cache_alloc;
426 } /* eet_cache_del */
428 /* internal string match. null friendly, catches same ptr */
430 eet_string_match(const char *s1,
433 /* both null- no match */
440 return (!strcmp(s1, s2));
441 } /* eet_string_match */
443 /* flush out writes to a v2 eet file */
445 eet_flush2(Eet_File *ef)
449 Eet_Error error = EET_ERROR_NONE;
450 int head[EET_FILE2_HEADER_COUNT];
451 int num_directory_entries = 0;
452 int num_dictionary_entries = 0;
453 int bytes_directory_entries = 0;
454 int bytes_dictionary_entries = 0;
455 int bytes_strings = 0;
457 int strings_offset = 0;
462 if (eet_check_pointer(ef))
463 return EET_ERROR_BAD_OBJECT;
465 if (eet_check_header(ef))
466 return EET_ERROR_EMPTY;
468 if (!ef->writes_pending)
469 return EET_ERROR_NONE;
471 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
472 || (ef->mode == EET_FILE_MODE_WRITE))
476 /* opening for write - delete old copy of file right away */
478 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
479 fp = fdopen(fd, "wb");
481 return EET_ERROR_NOT_WRITABLE;
483 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
486 return EET_ERROR_NOT_WRITABLE;
488 /* calculate string base offset and data base offset */
489 num = (1 << ef->header->directory->size);
490 for (i = 0; i < num; ++i)
492 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
494 num_directory_entries++;
495 bytes_strings += strlen(efn->name) + 1;
500 num_dictionary_entries = ef->ed->count;
502 for (i = 0; i < num_dictionary_entries; ++i)
503 bytes_strings += ef->ed->all[i].len;
506 /* calculate section bytes size */
507 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
508 num_directory_entries + EET_FILE2_HEADER_SIZE;
509 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
510 num_dictionary_entries;
512 /* calculate per entry offset */
513 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
514 data_offset = bytes_directory_entries + bytes_dictionary_entries +
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)
598 for (j = 0; j < ef->ed->count; ++j)
600 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
605 for (i = 0; i < num; i++)
607 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
609 if (fwrite(efn->data, efn->size, 1, fp) != 1)
614 /* flush all write to the file. */
616 // this is going to really cause trouble. if ANYTHING this needs to go into a
617 // thread spawned off - but even then...
618 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
619 // manual pages at eachother, but ext4 broke behavior that has been in place
620 // for decades and that 1000's of apps rely on daily - that is that one operation
621 // to disk is committed to disk BEFORE following operations, so the fs retains
622 // a consistent state
623 // fsync(fileno(fp));
625 /* append signature if required */
628 error = eet_identity_sign(fp, ef->key);
629 if (error != EET_ERROR_NONE)
633 /* no more writes pending */
634 ef->writes_pending = 0;
638 return EET_ERROR_NONE;
645 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
647 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
649 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
651 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
653 default: error = EET_ERROR_WRITE_ERROR; break;
665 if (++eet_init_count != 1)
666 return eet_init_count;
670 fprintf(stderr, "Eet: Eina init failed");
671 return --eet_init_count;
674 _eet_log_dom_global = eina_log_domain_register("eet", EET_DEFAULT_LOG_COLOR);
675 if (_eet_log_dom_global < 0)
677 EINA_LOG_ERR("Eet Can not create a general log domain.");
681 eina_lock_new(&eet_cache_lock);
683 if (!eet_node_init())
685 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
686 goto unregister_log_domain;
690 /* Before the library can be used, it must initialize itself if needed. */
691 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
693 gcry_check_version(NULL);
694 /* Disable warning messages about problems with the secure memory subsystem.
695 This command should be run right after gcry_check_version. */
696 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
697 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
698 enabling the use of secure memory. It also drops all extra privileges the
699 process has (i.e. if it is run as setuid (root)). If the argument nbytes
700 is 0, secure memory will be disabled. The minimum amount of secure memory
701 allocated is currently 16384 bytes; you may thus use a value of 1 to
702 request that default size. */
704 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
706 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
709 # ifdef EINA_HAVE_THREADS
710 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
712 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
714 # endif /* ifdef EINA_HAVE_THREADS */
715 if (gnutls_global_init())
718 #endif /* ifdef HAVE_GNUTLS */
720 ERR_load_crypto_strings();
721 OpenSSL_add_all_algorithms();
722 #endif /* ifdef HAVE_OPENSSL */
724 return eet_init_count;
730 unregister_log_domain:
731 eina_log_domain_unregister(_eet_log_dom_global);
732 _eet_log_dom_global = -1;
735 return --eet_init_count;
741 if (--eet_init_count != 0)
742 return eet_init_count;
747 eina_lock_free(&eet_cache_lock);
750 gnutls_global_deinit();
751 #endif /* ifdef HAVE_GNUTLS */
755 #endif /* ifdef HAVE_OPENSSL */
756 eina_log_domain_unregister(_eet_log_dom_global);
757 _eet_log_dom_global = -1;
760 return eet_init_count;
764 eet_sync(Eet_File *ef)
768 if (eet_check_pointer(ef))
769 return EET_ERROR_BAD_OBJECT;
771 if ((ef->mode != EET_FILE_MODE_WRITE) &&
772 (ef->mode != EET_FILE_MODE_READ_WRITE))
773 return EET_ERROR_NOT_WRITABLE;
775 if (!ef->writes_pending)
776 return EET_ERROR_NONE;
780 ret = eet_flush2(ef);
793 * We need to compute the list of eet file to close separately from the cache,
794 * due to eet_close removing them from the cache after each call.
797 for (i = 0; i < eet_writers_num; i++)
799 if (eet_writers[i]->references <= 0)
803 for (i = 0; i < eet_readers_num; i++)
805 if (eet_readers[i]->references <= 0)
811 Eet_File **closelist = NULL;
813 closelist = alloca(num * sizeof(Eet_File *));
815 for (i = 0; i < eet_writers_num; i++)
817 if (eet_writers[i]->references <= 0)
819 closelist[num] = eet_writers[i];
820 eet_writers[i]->delete_me_now = 1;
825 for (i = 0; i < eet_readers_num; i++)
827 if (eet_readers[i]->references <= 0)
829 closelist[num] = eet_readers[i];
830 eet_readers[i]->delete_me_now = 1;
835 for (i = 0; i < num; i++)
837 eet_internal_close(closelist[i], EINA_TRUE);
842 } /* eet_clearcache */
844 /* FIXME: MMAP race condition in READ_WRITE_MODE */
846 eet_internal_read2(Eet_File *ef)
848 const int *data = (const int *)ef->data;
849 const char *start = (const char *)ef->data;
851 unsigned long int bytes_directory_entries;
852 unsigned long int bytes_dictionary_entries;
853 unsigned long int signature_base_offset;
854 unsigned long int num_directory_entries;
855 unsigned long int num_dictionary_entries;
859 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
864 #define GET_INT(Value, Pointer, Index)\
866 Value = ntohl(*Pointer);\
868 Index += sizeof(int);\
871 /* get entries count and byte count */
872 GET_INT(num_directory_entries, data, idx);
873 /* get dictionary count and byte count */
874 GET_INT(num_dictionary_entries, data, idx);
876 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
877 num_directory_entries + EET_FILE2_HEADER_SIZE;
878 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
879 num_dictionary_entries;
881 /* we can't have <= 0 values here - invalid */
882 if (eet_test_close((num_directory_entries <= 0), ef))
885 /* we can't have more bytes directory and bytes in dictionaries than the size of the file */
886 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
890 /* allocate header */
891 ef->header = calloc(1, sizeof(Eet_File_Header));
892 if (eet_test_close(!ef->header, ef))
895 ef->header->magic = EET_MAGIC_FILE_HEADER;
897 /* allocate directory block in ram */
898 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
899 if (eet_test_close(!ef->header->directory, ef))
902 /* 8 bit hash table (256 buckets) */
903 ef->header->directory->size = 8;
904 /* allocate base hash table */
905 ef->header->directory->nodes =
906 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
907 if (eet_test_close(!ef->header->directory->nodes, ef))
910 signature_base_offset = 0;
912 /* actually read the directory block - all of it, into ram */
913 for (i = 0; i < num_directory_entries; ++i)
917 unsigned long int name_offset;
918 unsigned long int name_size;
922 /* out directory block is inconsistent - we have oveerun our */
923 /* dynamic block buffer before we finished scanning dir entries */
924 efn = malloc(sizeof(Eet_File_Node));
925 if (eet_test_close(!efn, ef))
927 if (efn) free(efn); /* yes i know - we only get here if
928 * efn is null/0 -> trying to shut up
929 * warning tools like cppcheck */
933 /* get entrie header */
934 GET_INT(efn->offset, data, idx);
935 GET_INT(efn->size, data, idx);
936 GET_INT(efn->data_size, data, idx);
937 GET_INT(name_offset, data, idx);
938 GET_INT(name_size, data, idx);
939 GET_INT(flag, data, idx);
941 efn->compression = flag & 0x1 ? 1 : 0;
942 efn->ciphered = flag & 0x2 ? 1 : 0;
943 efn->alias = flag & 0x4 ? 1 : 0;
945 #define EFN_TEST(Test, Ef, Efn)\
946 if (eet_test_close(Test, Ef))\
952 /* check data pointer position */
953 EFN_TEST(!((efn->size > 0)
954 && (efn->offset + efn->size <= ef->data_size)
955 && (efn->offset > bytes_dictionary_entries +
956 bytes_directory_entries)), ef, efn);
958 /* check name position */
959 EFN_TEST(!((name_size > 0)
960 && (name_offset + name_size < ef->data_size)
961 && (name_offset >= bytes_dictionary_entries +
962 bytes_directory_entries)), ef, efn);
964 name = start + name_offset;
966 /* check '\0' at the end of name string */
967 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
970 efn->name = (char *)name;
971 efn->name_size = name_size;
973 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
974 efn->next = ef->header->directory->nodes[hash];
975 ef->header->directory->nodes[hash] = efn;
977 /* read-only mode, so currently we have no data loaded */
978 if (ef->mode == EET_FILE_MODE_READ)
979 efn->data = NULL; /* read-write mode - read everything into ram */
982 efn->data = malloc(efn->size);
984 memcpy(efn->data, ef->data + efn->offset, efn->size);
987 /* compute the possible position of a signature */
988 if (signature_base_offset < efn->offset + efn->size)
989 signature_base_offset = efn->offset + efn->size;
994 if (num_dictionary_entries)
996 const int *dico = (const int *)ef->data +
997 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
998 EET_FILE2_HEADER_COUNT;
1001 if (eet_test_close((num_dictionary_entries *
1002 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1003 (bytes_dictionary_entries + bytes_directory_entries),
1007 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1008 if (eet_test_close(!ef->ed, ef))
1011 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1012 if (eet_test_close(!ef->ed->all, ef))
1015 ef->ed->count = num_dictionary_entries;
1016 ef->ed->total = num_dictionary_entries;
1017 ef->ed->start = start + bytes_dictionary_entries +
1018 bytes_directory_entries;
1019 ef->ed->end = ef->ed->start;
1021 for (j = 0; j < ef->ed->count; ++j)
1023 unsigned int offset;
1026 GET_INT(hash, dico, idx);
1027 GET_INT(offset, dico, idx);
1028 GET_INT(ef->ed->all[j].len, dico, idx);
1029 GET_INT(ef->ed->all[j].prev, dico, idx);
1030 GET_INT(ef->ed->all[j].next, dico, idx);
1032 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1033 So stick to int and check the value. */
1034 if (eet_test_close(hash & 0xFFFFFF00, ef))
1037 /* Check string position */
1038 if (eet_test_close(!((ef->ed->all[j].len > 0)
1040 (bytes_dictionary_entries +
1041 bytes_directory_entries))
1042 && (offset + ef->ed->all[j].len <
1043 ef->data_size)), ef))
1046 ef->ed->all[j].str = start + offset;
1048 if (ef->ed->all[j].str + ef->ed->all[j].len > ef->ed->end)
1049 ef->ed->end = ef->ed->all[j].str + ef->ed->all[j].len;
1051 /* Check '\0' at the end of the string */
1052 if (eet_test_close(ef->ed->all[j].str[ef->ed->all[j].len - 1] !=
1056 ef->ed->all[j].hash = hash;
1057 if (ef->ed->all[j].prev == -1)
1058 ef->ed->hash[hash] = j;
1060 /* compute the possible position of a signature */
1061 if (signature_base_offset < offset + ef->ed->all[j].len)
1062 signature_base_offset = offset + ef->ed->all[j].len;
1066 /* Check if the file is signed */
1067 ef->x509_der = NULL;
1068 ef->x509_length = 0;
1069 ef->signature = NULL;
1070 ef->signature_length = 0;
1072 if (signature_base_offset < ef->data_size)
1074 #ifdef HAVE_SIGNATURE
1075 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1076 signature_base_offset;
1077 ef->x509_der = eet_identity_check(ef->data,
1078 signature_base_offset,
1082 ef->data_size - signature_base_offset,
1084 &ef->signature_length,
1087 if (eet_test_close(!ef->x509_der, ef))
1090 #else /* ifdef HAVE_SIGNATURE */
1092 "This file could be signed but you didn't compile the necessary code to check the signature.");
1093 #endif /* ifdef HAVE_SIGNATURE */
1097 } /* eet_internal_read2 */
1099 #if EET_OLD_EET_FILE_FORMAT
1101 eet_internal_read1(Eet_File *ef)
1103 const unsigned char *dyn_buf = NULL;
1104 const unsigned char *p = NULL;
1105 unsigned long int byte_entries;
1106 unsigned long int num_entries;
1111 "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.",
1114 /* build header table if read mode */
1117 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1120 #define EXTRACT_INT(Value, Pointer, Index)\
1123 memcpy(&tmp, Pointer + Index, sizeof(int));\
1124 Value = ntohl(tmp);\
1125 Index += sizeof(int);\
1128 /* get entries count and byte count */
1129 EXTRACT_INT(num_entries, ef->data, idx);
1130 EXTRACT_INT(byte_entries, ef->data, idx);
1132 /* we can't have <= 0 values here - invalid */
1133 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1136 /* we can't have more entires than minimum bytes for those! invalid! */
1137 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1140 /* check we will not outrun the file limit */
1141 if (eet_test_close(((byte_entries + (int)sizeof(int) * 3) > ef->data_size),
1145 /* allocate header */
1146 ef->header = calloc(1, sizeof(Eet_File_Header));
1147 if (eet_test_close(!ef->header, ef))
1150 ef->header->magic = EET_MAGIC_FILE_HEADER;
1152 /* allocate directory block in ram */
1153 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1154 if (eet_test_close(!ef->header->directory, ef))
1157 /* 8 bit hash table (256 buckets) */
1158 ef->header->directory->size = 8;
1159 /* allocate base hash table */
1160 ef->header->directory->nodes =
1161 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1162 if (eet_test_close(!ef->header->directory->nodes, ef))
1165 /* actually read the directory block - all of it, into ram */
1166 dyn_buf = ef->data + idx;
1168 /* parse directory block */
1171 for (i = 0; i < num_entries; i++)
1180 #define HEADER_SIZE (sizeof(int) * 5)
1182 /* out directory block is inconsistent - we have oveerun our */
1183 /* dynamic block buffer before we finished scanning dir entries */
1184 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1187 /* allocate all the ram needed for this stored node accounting */
1188 efn = malloc (sizeof(Eet_File_Node));
1189 if (eet_test_close(!efn, ef))
1191 if (efn) free(efn); /* yes i know - we only get here if
1192 * efn is null/0 -> trying to shut up
1193 * warning tools like cppcheck */
1197 /* get entrie header */
1198 EXTRACT_INT(efn->offset, p, indexn);
1199 EXTRACT_INT(efn->compression, p, indexn);
1200 EXTRACT_INT(efn->size, p, indexn);
1201 EXTRACT_INT(efn->data_size, p, indexn);
1202 EXTRACT_INT(name_size, p, indexn);
1204 efn->name_size = name_size;
1209 if (eet_test_close(efn->size <= 0, ef))
1215 /* invalid name_size */
1216 if (eet_test_close(name_size <= 0, ef))
1222 /* reading name would mean falling off end of dyn_buf - invalid */
1223 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1229 /* This code is useless if we dont want backward compatibility */
1231 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1234 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1238 efn->name = malloc(sizeof(char) * name_size + 1);
1239 if (eet_test_close(!efn->name, ef))
1245 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1246 efn->name[name_size] = 0;
1249 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1254 /* The only really useful peace of code for efn->name (no backward compatibility) */
1255 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1257 /* get hash bucket it should go in */
1258 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1259 efn->next = ef->header->directory->nodes[hash];
1260 ef->header->directory->nodes[hash] = efn;
1262 /* read-only mode, so currently we have no data loaded */
1263 if (ef->mode == EET_FILE_MODE_READ)
1264 efn->data = NULL; /* read-write mode - read everything into ram */
1267 data = malloc(efn->size);
1269 memcpy(data, ef->data + efn->offset, efn->size);
1275 p += HEADER_SIZE + name_size;
1278 } /* eet_internal_read1 */
1280 #endif /* if EET_OLD_EET_FILE_FORMAT */
1283 * this should only be called when the cache lock is already held
1284 * (We could drop this restriction if we add a parameter to eet_test_close
1285 * that indicates if the lock is held or not. For now it is easiest
1286 * to just require that it is always held.)
1289 eet_internal_read(Eet_File *ef)
1291 const int *data = (const int *)ef->data;
1293 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1296 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1299 switch (ntohl(*data))
1301 #if EET_OLD_EET_FILE_FORMAT
1302 case EET_MAGIC_FILE:
1303 return eet_internal_read1(ef);
1305 #endif /* if EET_OLD_EET_FILE_FORMAT */
1306 case EET_MAGIC_FILE2:
1307 return eet_internal_read2(ef);
1310 ef->delete_me_now = 1;
1311 eet_internal_close(ef, EINA_TRUE);
1316 } /* eet_internal_read */
1319 eet_internal_close(Eet_File *ef,
1324 /* check to see its' an eet file pointer */
1325 if (eet_check_pointer(ef))
1326 return EET_ERROR_BAD_OBJECT;
1333 /* if its still referenced - dont go any further */
1334 if (ef->references > 0)
1336 /* flush any writes */
1337 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1338 (ef->mode == EET_FILE_MODE_READ_WRITE))
1343 err = eet_flush2(ef);
1345 eet_identity_unref(ef->key);
1348 /* if not urgent to delete it - dont free it - leave it in cache */
1349 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1352 /* remove from cache */
1353 if (ef->mode == EET_FILE_MODE_READ)
1354 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1355 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1356 (ef->mode == EET_FILE_MODE_READ_WRITE))
1357 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1359 /* we can unlock the cache now */
1368 if (ef->header->directory)
1370 if (ef->header->directory->nodes)
1374 num = (1 << ef->header->directory->size);
1375 for (i = 0; i < num; i++)
1379 while ((efn = ef->header->directory->nodes[i]))
1384 ef->header->directory->nodes[i] = efn->next;
1392 free(ef->header->directory->nodes);
1395 free(ef->header->directory);
1401 eet_dictionary_free(ef->ed);
1409 eina_file_map_free(ef->readfp, (void *) ef->data);
1411 eina_file_close(ef->readfp);
1414 /* zero out ram for struct - caution tactic against stale memory use */
1415 memset(ef, 0, sizeof(Eet_File));
1425 return EET_ERROR_NONE;
1426 } /* eet_internal_close */
1429 eet_memopen_read(const void *data,
1434 if (!data || size == 0)
1437 ef = malloc (sizeof (Eet_File));
1445 ef->magic = EET_MAGIC_FILE;
1447 ef->mode = EET_FILE_MODE_READ;
1449 ef->delete_me_now = 1;
1452 ef->data_size = size;
1454 ef->sha1_length = 0;
1456 /* eet_internal_read expects the cache lock to be held when it is called */
1458 ef = eet_internal_read(ef);
1461 } /* eet_memopen_read */
1464 eet_open(const char *file,
1470 unsigned long int size;
1475 /* find the current file handle in cache*/
1478 if (mode == EET_FILE_MODE_READ)
1480 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1485 ef->delete_me_now = 1;
1486 eet_internal_close(ef, EINA_TRUE);
1489 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1491 else if ((mode == EET_FILE_MODE_WRITE) ||
1492 (mode == EET_FILE_MODE_READ_WRITE))
1494 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1497 ef->delete_me_now = 1;
1499 eet_internal_close(ef, EINA_TRUE);
1502 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1505 /* try open the file based on mode */
1506 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1508 /* Prevent garbage in futur comparison. */
1509 fp = eina_file_open(file, EINA_FALSE);
1513 size = eina_file_size_get(fp);
1515 if (size < ((int)sizeof(int) * 3))
1517 eina_file_close(fp);
1526 if (!fp && mode == EET_FILE_MODE_READ)
1531 if (mode != EET_FILE_MODE_WRITE)
1540 if (ef && ef->readfp != fp)
1542 ef->delete_me_now = 1;
1544 eet_internal_close(ef, EINA_TRUE);
1550 /* reference it up and return it */
1552 eina_file_close(fp);
1559 file_len = strlen(file) + 1;
1561 /* Allocate struct for eet file and have it zero'd out */
1562 ef = malloc(sizeof(Eet_File) + file_len);
1566 /* fill some of the members */
1570 ef->path = ((char *)ef) + sizeof(Eet_File);
1571 memcpy(ef->path, file, file_len);
1572 ef->magic = EET_MAGIC_FILE;
1576 ef->writes_pending = 0;
1577 ef->delete_me_now = 0;
1581 ef->sha1_length = 0;
1583 ef->ed = (mode == EET_FILE_MODE_WRITE)
1584 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1585 eet_dictionary_add() : NULL;
1588 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1591 /* if we can't open - bail out */
1592 if (eet_test_close(!ef->readfp, ef))
1595 /* if we opened for read or read-write */
1596 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1598 ef->data_size = size;
1599 ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL);
1600 if (eet_test_close((ef->data == NULL), ef))
1603 ef = eet_internal_read(ef);
1610 if (ef->references == 1)
1612 if (ef->mode == EET_FILE_MODE_READ)
1613 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1614 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1615 (ef->mode == EET_FILE_MODE_READ_WRITE))
1616 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1628 eet_mode_get(Eet_File *ef)
1630 /* check to see its' an eet file pointer */
1631 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1632 return EET_FILE_MODE_INVALID;
1635 } /* eet_mode_get */
1638 eet_identity_x509(Eet_File *ef,
1645 *der_length = ef->x509_length;
1647 return ef->x509_der;
1648 } /* eet_identity_x509 */
1651 eet_identity_signature(Eet_File *ef,
1652 int *signature_length)
1657 if (signature_length)
1658 *signature_length = ef->signature_length;
1660 return ef->signature;
1661 } /* eet_identity_signature */
1664 eet_identity_sha1(Eet_File *ef,
1668 ef->sha1 = eet_identity_compute_sha1(ef->data,
1673 *sha1_length = ef->sha1_length;
1676 } /* eet_identity_sha1 */
1679 eet_identity_set(Eet_File *ef,
1685 return EET_ERROR_BAD_OBJECT;
1689 eet_identity_ref(ef->key);
1690 eet_identity_unref(tmp);
1692 /* flags that writes are pending */
1693 ef->writes_pending = 1;
1695 return EET_ERROR_NONE;
1696 } /* eet_identity_set */
1699 eet_close(Eet_File *ef)
1701 return eet_internal_close(ef, EINA_FALSE);
1705 eet_read_cipher(Eet_File *ef,
1708 const char *cipher_key)
1712 unsigned long int size = 0;
1717 /* check to see its' an eet file pointer */
1718 if (eet_check_pointer(ef))
1724 if ((ef->mode != EET_FILE_MODE_READ) &&
1725 (ef->mode != EET_FILE_MODE_READ_WRITE))
1728 /* no header, return NULL */
1729 if (eet_check_header(ef))
1734 /* hunt hash bucket */
1735 efn = find_node_by_name(ef, name);
1739 /* get size (uncompressed, if compressed at all) */
1740 size = efn->data_size;
1743 data = malloc(size);
1747 /* uncompressed data */
1748 if (efn->compression == 0)
1750 void *data_deciphered = NULL;
1751 unsigned int data_deciphered_sz = 0;
1752 /* if we already have the data in ram... copy that */
1754 if (efn->ciphered && efn->size > size)
1757 data = realloc(data, efn->size);
1761 memcpy(data, efn->data, size);
1763 if (!read_data_from_disk(ef, efn, data, size))
1766 if (efn->ciphered && cipher_key)
1768 if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key),
1769 &data_deciphered, &data_deciphered_sz))
1771 if (data_deciphered)
1772 free(data_deciphered);
1778 data = data_deciphered;
1779 size = data_deciphered_sz;
1782 /* compressed data */
1785 void *tmp_data = NULL;
1786 void *data_deciphered = NULL;
1787 unsigned int data_deciphered_sz = 0;
1789 int compr_size = efn->size;
1792 /* if we already have the data in ram... copy that */
1794 tmp_data = efn->data;
1797 tmp_data = malloc(compr_size);
1803 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1810 if (efn->ciphered && cipher_key)
1812 if (eet_decipher(tmp_data, compr_size, cipher_key,
1813 strlen(cipher_key), &data_deciphered,
1814 &data_deciphered_sz))
1819 if (data_deciphered)
1820 free(data_deciphered);
1828 tmp_data = data_deciphered;
1829 compr_size = data_deciphered_sz;
1834 if (uncompress((Bytef *)data, &dlen,
1835 tmp_data, (uLongf)compr_size))
1853 if (data[size - 1] != '\0')
1856 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1863 /* fill in return values */
1873 } /* eet_read_cipher */
1876 eet_read(Eet_File *ef,
1880 return eet_read_cipher(ef, name, size_ret, NULL);
1884 eet_read_direct(Eet_File *ef,
1889 const char *data = NULL;
1895 /* check to see its' an eet file pointer */
1896 if (eet_check_pointer(ef))
1902 if ((ef->mode != EET_FILE_MODE_READ) &&
1903 (ef->mode != EET_FILE_MODE_READ_WRITE))
1906 /* no header, return NULL */
1907 if (eet_check_header(ef))
1912 /* hunt hash bucket */
1913 efn = find_node_by_name(ef, name);
1917 /* trick to detect data in memory instead of mmaped from disk */
1918 if (efn->offset > ef->data_size && !efn->data)
1921 /* get size (uncompressed, if compressed at all) */
1922 size = efn->data_size;
1926 data = efn->data ? efn->data : ef->data + efn->offset;
1928 /* handle alias case */
1929 if (efn->compression)
1932 int compr_size = efn->size;
1935 tmp = alloca(sizeof (compr_size));
1938 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1939 (uLongf)compr_size))
1942 if (tmp[compr_size - 1] != '\0')
1947 return eet_read_direct(ef, tmp, size_ret);
1953 if (data[size - 1] != '\0')
1958 return eet_read_direct(ef, data, size_ret);
1961 /* uncompressed data */
1962 if (efn->compression == 0
1963 && efn->ciphered == 0)
1964 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1968 /* fill in return values */
1979 } /* eet_read_direct */
1982 eet_alias(Eet_File *ef,
1984 const char *destination,
1989 Eina_Bool exists_already = EINA_FALSE;
1993 /* check to see its' an eet file pointer */
1994 if (eet_check_pointer(ef))
1997 if ((!name) || (!destination))
2000 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2001 (ef->mode != EET_FILE_MODE_READ_WRITE))
2008 /* allocate header */
2009 ef->header = calloc(1, sizeof(Eet_File_Header));
2013 ef->header->magic = EET_MAGIC_FILE_HEADER;
2014 /* allocate directory block in ram */
2015 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2016 if (!ef->header->directory)
2023 /* 8 bit hash table (256 buckets) */
2024 ef->header->directory->size = 8;
2025 /* allocate base hash table */
2026 ef->header->directory->nodes =
2027 calloc(1, sizeof(Eet_File_Node *) *
2028 (1 << ef->header->directory->size));
2029 if (!ef->header->directory->nodes)
2031 free(ef->header->directory);
2037 /* figure hash bucket */
2038 hash = _eet_hash_gen(name, ef->header->directory->size);
2041 12 + (((strlen(destination) + 1) * 101) / 100)
2042 : strlen(destination) + 1;
2044 data2 = malloc(data_size);
2048 /* if we want to compress */
2053 /* compress the data with max compression */
2054 buflen = (uLongf)data_size;
2055 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2056 (uLong)strlen(destination) + 1,
2057 Z_BEST_COMPRESSION) != Z_OK)
2063 /* record compressed chunk size */
2064 data_size = (int)buflen;
2065 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2068 data_size = strlen(destination) + 1;
2074 data3 = realloc(data2, data_size);
2081 memcpy(data2, destination, data_size);
2083 /* Does this node already exist? */
2084 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2087 if ((efn->name) && (eet_string_match(efn->name, name)))
2092 efn->compression = !!comp;
2093 efn->size = data_size;
2094 efn->data_size = strlen(destination) + 1;
2096 /* Put the offset above the limit to avoid direct access */
2097 efn->offset = ef->data_size + 1;
2098 exists_already = EINA_TRUE;
2103 if (!exists_already)
2105 efn = malloc(sizeof(Eet_File_Node));
2112 efn->name = strdup(name);
2113 efn->name_size = strlen(efn->name) + 1;
2116 efn->next = ef->header->directory->nodes[hash];
2117 ef->header->directory->nodes[hash] = efn;
2118 /* Put the offset above the limit to avoid direct access */
2119 efn->offset = ef->data_size + 1;
2122 efn->compression = !!comp;
2123 efn->size = data_size;
2124 efn->data_size = strlen(destination) + 1;
2128 /* flags that writes are pending */
2129 ef->writes_pending = 1;
2140 eet_write_cipher(Eet_File *ef,
2145 const char *cipher_key)
2149 int exists_already = 0;
2153 /* check to see its' an eet file pointer */
2154 if (eet_check_pointer(ef))
2157 if ((!name) || (!data) || (size <= 0))
2160 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2161 (ef->mode != EET_FILE_MODE_READ_WRITE))
2168 /* allocate header */
2169 ef->header = calloc(1, sizeof(Eet_File_Header));
2173 ef->header->magic = EET_MAGIC_FILE_HEADER;
2174 /* allocate directory block in ram */
2175 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2176 if (!ef->header->directory)
2183 /* 8 bit hash table (256 buckets) */
2184 ef->header->directory->size = 8;
2185 /* allocate base hash table */
2186 ef->header->directory->nodes =
2187 calloc(1, sizeof(Eet_File_Node *) *
2188 (1 << ef->header->directory->size));
2189 if (!ef->header->directory->nodes)
2191 free(ef->header->directory);
2197 /* figure hash bucket */
2198 hash = _eet_hash_gen(name, ef->header->directory->size);
2200 data_size = comp ? 12 + ((size * 101) / 100) : size;
2202 if (comp || !cipher_key)
2204 data2 = malloc(data_size);
2209 /* if we want to compress */
2214 /* compress the data with max compression */
2215 buflen = (uLongf)data_size;
2216 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2217 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2223 /* record compressed chunk size */
2224 data_size = (int)buflen;
2225 if (data_size < 0 || data_size >= size)
2234 data3 = realloc(data2, data_size);
2242 void *data_ciphered = NULL;
2243 unsigned int data_ciphered_sz = 0;
2246 tmp = comp ? data2 : data;
2247 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2248 &data_ciphered, &data_ciphered_sz))
2253 data2 = data_ciphered;
2254 data_size = data_ciphered_sz;
2259 free(data_ciphered);
2266 memcpy(data2, data, size);
2268 /* Does this node already exist? */
2269 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2272 if ((efn->name) && (eet_string_match(efn->name, name)))
2276 efn->ciphered = cipher_key ? 1 : 0;
2277 efn->compression = !!comp;
2278 efn->size = data_size;
2279 efn->data_size = size;
2281 /* Put the offset above the limit to avoid direct access */
2282 efn->offset = ef->data_size + 1;
2287 if (!exists_already)
2289 efn = malloc(sizeof(Eet_File_Node));
2296 efn->name = strdup(name);
2297 efn->name_size = strlen(efn->name) + 1;
2300 efn->next = ef->header->directory->nodes[hash];
2301 ef->header->directory->nodes[hash] = efn;
2302 /* Put the offset above the limit to avoid direct access */
2303 efn->offset = ef->data_size + 1;
2305 efn->ciphered = cipher_key ? 1 : 0;
2306 efn->compression = !!comp;
2307 efn->size = data_size;
2308 efn->data_size = size;
2312 /* flags that writes are pending */
2313 ef->writes_pending = 1;
2320 } /* eet_write_cipher */
2323 eet_write(Eet_File *ef,
2329 return eet_write_cipher(ef, name, data, size, comp, NULL);
2333 eet_delete(Eet_File *ef,
2337 Eet_File_Node *pefn;
2339 int exists_already = 0;
2341 /* check to see its' an eet file pointer */
2342 if (eet_check_pointer(ef))
2348 /* deleting keys is only possible in RW or WRITE mode */
2349 if (ef->mode == EET_FILE_MODE_READ)
2352 if (eet_check_header(ef))
2357 /* figure hash bucket */
2358 hash = _eet_hash_gen(name, ef->header->directory->size);
2360 /* Does this node already exist? */
2361 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2363 pefn = efn, efn = efn->next)
2366 if (eet_string_match(efn->name, name))
2372 ef->header->directory->nodes[hash] = efn->next;
2374 pefn->next = efn->next;
2384 /* flags that writes are pending */
2386 ef->writes_pending = 1;
2390 /* update access time */
2391 return exists_already;
2394 EAPI Eet_Dictionary *
2395 eet_dictionary_get(Eet_File *ef)
2397 if (eet_check_pointer(ef))
2401 } /* eet_dictionary_get */
2404 eet_list(Eet_File *ef,
2409 char **list_ret = NULL;
2411 int list_count_alloc = 0;
2414 /* check to see its' an eet file pointer */
2415 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2417 ((ef->mode != EET_FILE_MODE_READ) &&
2418 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2426 if (!strcmp(glob, "*"))
2431 /* loop through all entries */
2432 num = (1 << ef->header->directory->size);
2433 for (i = 0; i < num; i++)
2435 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2437 /* if the entry matches the input glob
2438 * check for * explicitly, because on some systems, * isn't well
2441 if ((!glob) || !fnmatch(glob, efn->name, 0))
2443 /* add it to our list */
2446 /* only realloc in 32 entry chunks */
2447 if (list_count > list_count_alloc)
2449 char **new_list = NULL;
2451 list_count_alloc += 64;
2453 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2461 list_ret = new_list;
2464 /* put pointer of name string in */
2465 list_ret[list_count - 1] = efn->name;
2472 /* return count and list */
2474 *count_ret = list_count;
2488 eet_num_entries(Eet_File *ef)
2490 int i, num, ret = 0;
2493 /* check to see its' an eet file pointer */
2494 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2495 ((ef->mode != EET_FILE_MODE_READ) &&
2496 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2501 /* loop through all entries */
2502 num = (1 << ef->header->directory->size);
2503 for (i = 0; i < num; i++)
2505 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2512 } /* eet_num_entries */
2514 static Eet_File_Node *
2515 find_node_by_name(Eet_File *ef,
2521 /* get hash bucket this should be in */
2522 hash = _eet_hash_gen(name, ef->header->directory->size);
2524 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2526 if (eet_string_match(efn->name, name))
2531 } /* find_node_by_name */
2534 read_data_from_disk(Eet_File *ef,
2539 if (efn->offset > ef->data_size)
2545 if ((efn->offset + len) > ef->data_size)
2548 memcpy(buf, ef->data + efn->offset, len);
2551 } /* read_data_from_disk */