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>
38 #endif /* ifdef HAVE_UNISTD_H */
40 #ifdef HAVE_NETINET_IN_H
41 # include <netinet/in.h>
42 #endif /* ifdef HAVE_NETINET_IN_H */
46 #endif /* ifdef HAVE_EVIL */
51 # include <gnutls/gnutls.h>
53 #endif /* ifdef HAVE_GNUTLS */
56 # include <openssl/err.h>
57 # include <openssl/evp.h>
58 #endif /* ifdef HAVE_OPENSSL */
60 #ifdef EINA_HAVE_THREADS
62 GCRY_THREAD_OPTION_PTHREAD_IMPL;
63 # endif /* ifdef HAVE_GNUTLS */
64 #endif /* ifdef EINA_HAVE_THREADS */
67 #include "Eet_private.h"
74 static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV };
75 EAPI Eet_Version *eet_version = &_version;
79 #endif /* ifdef HAVE_REALPATH */
81 #define EET_MAGIC_FILE 0x1ee7ff00
82 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
84 #define EET_MAGIC_FILE2 0x1ee70f42
86 typedef struct _Eet_File_Header Eet_File_Header;
87 typedef struct _Eet_File_Node Eet_File_Node;
88 typedef struct _Eet_File_Directory Eet_File_Directory;
94 Eet_File_Header *header;
97 const unsigned char *data;
99 const void *signature;
107 unsigned long int data_size;
109 unsigned int signature_length;
114 unsigned char writes_pending : 1;
115 unsigned char delete_me_now : 1;
118 struct _Eet_File_Header
121 Eet_File_Directory *directory;
124 struct _Eet_File_Directory
127 Eet_File_Node **nodes;
130 struct _Eet_File_Node
134 Eet_File_Node *next; /* FIXME: make buckets linked lists */
136 unsigned long int offset;
137 unsigned long int dictionary_offset;
138 unsigned long int name_offset;
140 unsigned int name_size;
142 unsigned int data_size;
144 unsigned char free_name : 1;
145 unsigned char compression : 1;
146 unsigned char ciphered : 1;
147 unsigned char alias : 1;
152 /* NB: all int's are stored in network byte order on disk */
154 int magic; /* magic number ie 0x1ee7ff00 */
155 int num_directory_entries; /* number of directory entries to follow */
156 int bytes_directory_entries; /* bytes of directory entries to follow */
159 int offset; /* bytes offset into file for data chunk */
160 int flags; /* flags - for now 0 = uncompressed and clear, 1 = compressed and clear, 2 = uncompressed and ciphered, 3 = compressed and ciphered */
161 int size; /* size of the data chunk */
162 int data_size; /* size of the (uncompressed) data chunk */
163 int name_size; /* length in bytes of the name field */
164 char name[name_size]; /* name string (variable length) and \0 terminated */
165 } directory[num_directory_entries];
166 /* and now startes the data stream... */
171 /* NB: all int's are stored in network byte order on disk */
173 int magic; /* magic number ie 0x1ee70f42 */
174 int num_directory_entries; /* number of directory entries to follow */
175 int num_dictionary_entries; /* number of dictionary entries to follow */
178 int data_offset; /* bytes offset into file for data chunk */
179 int size; /* size of the data chunk */
180 int data_size; /* size of the (uncompressed) data chunk */
181 int name_offset; /* bytes offset into file for name string */
182 int name_size; /* length in bytes of the name field */
183 int flags; /* bit flags - for now:
184 bit 0 => compresion on/off
185 bit 1 => ciphered on/off
188 } directory[num_directory_entries];
196 } dictionary[num_dictionary_entries];
197 /* now start the string stream. */
198 /* and right after them the data stream. */
199 int magic_sign; /* Optional, only if the eet file is signed. */
200 int signature_length; /* Signature length. */
201 int x509_length; /* Public certificate that signed the file. */
202 char signature[signature_length]; /* The signature. */
203 char x509[x509_length]; /* The public certificate. */
206 #define EET_FILE2_HEADER_COUNT 3
207 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
208 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
210 #define EET_FILE2_HEADER_SIZE (sizeof(int) *\
211 EET_FILE2_HEADER_COUNT)
212 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) *\
213 EET_FILE2_DIRECTORY_ENTRY_COUNT)
214 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) *\
215 EET_FILE2_DICTIONARY_ENTRY_COUNT)
217 /* prototypes of internal calls */
218 static Eet_File * eet_cache_find(const char *path,
221 static void eet_cache_add(Eet_File *ef,
225 static void eet_cache_del(Eet_File *ef,
229 static int eet_string_match(const char *s1, const char *s2);
231 static Eet_Error eet_flush(Eet_File *ef);
233 static Eet_Error eet_flush2(Eet_File *ef);
234 static Eet_File_Node * find_node_by_name(Eet_File *ef, const char *name);
235 static int read_data_from_disk(Eet_File *ef,
240 static Eet_Error eet_internal_close(Eet_File *ef, Eina_Bool locked);
242 static Eina_Lock eet_cache_lock;
244 #define LOCK_CACHE eina_lock_take(&eet_cache_lock)
245 #define UNLOCK_CACHE eina_lock_release(&eet_cache_lock)
247 #define INIT_FILE(File) eina_lock_new(&File->file_lock)
248 #define LOCK_FILE(File) eina_lock_take(&File->file_lock)
249 #define UNLOCK_FILE(File) eina_lock_release(&File->file_lock)
250 #define DESTROY_FILE(File) eina_lock_free(&File->file_lock)
252 /* cache. i don't expect this to ever be large, so arrays will do */
253 static int eet_writers_num = 0;
254 static int eet_writers_alloc = 0;
255 static Eet_File **eet_writers = NULL;
256 static int eet_readers_num = 0;
257 static int eet_readers_alloc = 0;
258 static Eet_File **eet_readers = NULL;
259 static int eet_init_count = 0;
261 /* log domain variable */
262 int _eet_log_dom_global = -1;
264 /* Check to see its' an eet file pointer */
266 eet_check_pointer(const Eet_File *ef)
268 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
272 } /* eet_check_pointer */
275 eet_check_header(const Eet_File *ef)
280 if (!ef->header->directory)
284 } /* eet_check_header */
287 eet_test_close(int test,
292 ef->delete_me_now = 1;
293 eet_internal_close(ef, EINA_TRUE);
297 } /* eet_test_close */
299 /* find an eet file in the currently in use cache */
301 eet_cache_find(const char *path,
308 for (i = 0; i < cache_num; i++)
310 /* if matches real path - return it */
311 if (eet_string_match(cache[i]->path, path))
312 if (!cache[i]->delete_me_now)
319 } /* eet_cache_find */
321 /* add to end of cache */
322 /* this should only be called when the cache lock is already held */
324 eet_cache_add(Eet_File *ef,
329 Eet_File **new_cache;
333 new_cache_num = *cache_num;
334 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
336 Eet_File *del_ef = NULL;
340 for (i = 0; i < new_cache_num; i++)
342 if (new_cache[i]->references == 0)
344 del_ef = new_cache[i];
351 del_ef->delete_me_now = 1;
352 eet_internal_close(del_ef, EINA_TRUE);
357 new_cache_num = *cache_num;
358 new_cache_alloc = *cache_alloc;
360 if (new_cache_num > new_cache_alloc)
362 new_cache_alloc += 16;
363 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
366 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
371 new_cache[new_cache_num - 1] = ef;
373 *cache_num = new_cache_num;
374 *cache_alloc = new_cache_alloc;
375 } /* eet_cache_add */
377 /* delete from cache */
378 /* this should only be called when the cache lock is already held */
380 eet_cache_del(Eet_File *ef,
385 Eet_File **new_cache;
386 int new_cache_num, new_cache_alloc;
390 new_cache_num = *cache_num;
391 new_cache_alloc = *cache_alloc;
392 if (new_cache_num <= 0)
395 for (i = 0; i < new_cache_num; i++)
397 if (new_cache[i] == ef)
401 if (i >= new_cache_num)
405 for (j = i; j < new_cache_num; j++)
406 new_cache[j] = new_cache[j + 1];
408 if (new_cache_num <= (new_cache_alloc - 16))
410 new_cache_alloc -= 16;
411 if (new_cache_num > 0)
413 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
416 CRIT("BAD ERROR! Eet realloc of cache list failed. Abort");
428 *cache_num = new_cache_num;
429 *cache_alloc = new_cache_alloc;
430 } /* eet_cache_del */
432 /* internal string match. null friendly, catches same ptr */
434 eet_string_match(const char *s1,
437 /* both null- no match */
444 return (!strcmp(s1, s2));
445 } /* eet_string_match */
447 /* flush out writes to a v2 eet file */
449 eet_flush2(Eet_File *ef)
453 Eet_Error error = EET_ERROR_NONE;
454 int head[EET_FILE2_HEADER_COUNT];
455 int num_directory_entries = 0;
456 int num_dictionary_entries = 0;
457 int bytes_directory_entries = 0;
458 int bytes_dictionary_entries = 0;
459 int bytes_strings = 0;
461 int strings_offset = 0;
466 if (eet_check_pointer(ef))
467 return EET_ERROR_BAD_OBJECT;
469 if (eet_check_header(ef))
470 return EET_ERROR_EMPTY;
472 if (!ef->writes_pending)
473 return EET_ERROR_NONE;
475 if ((ef->mode == EET_FILE_MODE_READ_WRITE)
476 || (ef->mode == EET_FILE_MODE_WRITE))
480 /* opening for write - delete old copy of file right away */
482 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR);
483 fp = fdopen(fd, "wb");
485 return EET_ERROR_NOT_WRITABLE;
487 fcntl(fileno(fp), F_SETFD, FD_CLOEXEC);
490 return EET_ERROR_NOT_WRITABLE;
492 /* calculate string base offset and data base offset */
493 num = (1 << ef->header->directory->size);
494 for (i = 0; i < num; ++i)
496 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
498 num_directory_entries++;
499 bytes_strings += strlen(efn->name) + 1;
504 num_dictionary_entries = ef->ed->count;
506 for (i = 0; i < num_dictionary_entries; ++i)
507 bytes_strings += ef->ed->all[i].len;
510 /* calculate section bytes size */
511 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
512 num_directory_entries + EET_FILE2_HEADER_SIZE;
513 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
514 num_dictionary_entries;
516 /* calculate per entry offset */
517 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
518 data_offset = bytes_directory_entries + bytes_dictionary_entries +
521 for (i = 0; i < num; ++i)
523 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
525 efn->offset = data_offset;
526 data_offset += efn->size;
528 efn->name_offset = strings_offset;
529 strings_offset += efn->name_size;
533 /* calculate dictionary strings offset */
535 ef->ed->offset = strings_offset;
537 /* go thru and write the header */
538 head[0] = (int)htonl((unsigned int)EET_MAGIC_FILE2);
539 head[1] = (int)htonl((unsigned int)num_directory_entries);
540 head[2] = (int)htonl((unsigned int)num_dictionary_entries);
542 fseek(fp, 0, SEEK_SET);
543 if (fwrite(head, sizeof (head), 1, fp) != 1)
546 /* write directories entry */
547 for (i = 0; i < num; i++)
549 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
552 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
554 flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression;
556 ibuf[0] = (int)htonl((unsigned int)efn->offset);
557 ibuf[1] = (int)htonl((unsigned int)efn->size);
558 ibuf[2] = (int)htonl((unsigned int)efn->data_size);
559 ibuf[3] = (int)htonl((unsigned int)efn->name_offset);
560 ibuf[4] = (int)htonl((unsigned int)efn->name_size);
561 ibuf[5] = (int)htonl((unsigned int)flag);
563 if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1)
568 /* write dictionary */
571 int offset = strings_offset;
573 for (j = 0; j < ef->ed->count; ++j)
575 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
577 sbuf[0] = (int)htonl((unsigned int)ef->ed->all[j].hash);
578 sbuf[1] = (int)htonl((unsigned int)offset);
579 sbuf[2] = (int)htonl((unsigned int)ef->ed->all[j].len);
580 sbuf[3] = (int)htonl((unsigned int)ef->ed->all[j].prev);
581 sbuf[4] = (int)htonl((unsigned int)ef->ed->all[j].next);
583 offset += ef->ed->all[j].len;
585 if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1)
590 /* write directories name */
591 for (i = 0; i < num; i++)
593 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
595 if (fwrite(efn->name, efn->name_size, 1, fp) != 1)
602 for (j = 0; j < ef->ed->count; ++j)
604 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1)
609 for (i = 0; i < num; i++)
611 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
613 if (fwrite(efn->data, efn->size, 1, fp) != 1)
618 /* flush all write to the file. */
620 // this is going to really cause trouble. if ANYTHING this needs to go into a
621 // thread spawned off - but even then...
622 // in this case... ext4 is "wrong". (yes we can jump up and down and point posix
623 // manual pages at eachother, but ext4 broke behavior that has been in place
624 // for decades and that 1000's of apps rely on daily - that is that one operation
625 // to disk is committed to disk BEFORE following operations, so the fs retains
626 // a consistent state
627 // fsync(fileno(fp));
629 /* append signature if required */
632 error = eet_identity_sign(fp, ef->key);
633 if (error != EET_ERROR_NONE)
637 /* no more writes pending */
638 ef->writes_pending = 0;
642 return EET_ERROR_NONE;
649 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
651 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
653 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
655 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
657 default: error = EET_ERROR_WRITE_ERROR; break;
669 if (++eet_init_count != 1)
670 return eet_init_count;
674 fprintf(stderr, "Eet: Eina init failed");
675 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 eina_lock_new(&eet_cache_lock);
687 if (!eet_node_init())
689 EINA_LOG_ERR("Eet: Eet_Node mempool creation failed");
690 goto unregister_log_domain;
694 /* Before the library can be used, it must initialize itself if needed. */
695 if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0)
697 gcry_check_version(NULL);
698 /* Disable warning messages about problems with the secure memory subsystem.
699 This command should be run right after gcry_check_version. */
700 if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN))
701 goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus
702 enabling the use of secure memory. It also drops all extra privileges the
703 process has (i.e. if it is run as setuid (root)). If the argument nbytes
704 is 0, secure memory will be disabled. The minimum amount of secure memory
705 allocated is currently 16384 bytes; you may thus use a value of 1 to
706 request that default size. */
708 if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0))
710 "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !");
713 # ifdef EINA_HAVE_THREADS
714 if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
716 "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!");
718 # endif /* ifdef EINA_HAVE_THREADS */
719 if (gnutls_global_init())
722 #endif /* ifdef HAVE_GNUTLS */
724 ERR_load_crypto_strings();
725 OpenSSL_add_all_algorithms();
726 #endif /* ifdef HAVE_OPENSSL */
728 return eet_init_count;
734 unregister_log_domain:
735 eina_log_domain_unregister(_eet_log_dom_global);
736 _eet_log_dom_global = -1;
739 return --eet_init_count;
745 if (--eet_init_count != 0)
746 return eet_init_count;
751 eina_lock_free(&eet_cache_lock);
754 gnutls_global_deinit();
755 #endif /* ifdef HAVE_GNUTLS */
759 #endif /* ifdef HAVE_OPENSSL */
760 eina_log_domain_unregister(_eet_log_dom_global);
761 _eet_log_dom_global = -1;
764 return eet_init_count;
768 eet_sync(Eet_File *ef)
772 if (eet_check_pointer(ef))
773 return EET_ERROR_BAD_OBJECT;
775 if ((ef->mode != EET_FILE_MODE_WRITE) &&
776 (ef->mode != EET_FILE_MODE_READ_WRITE))
777 return EET_ERROR_NOT_WRITABLE;
779 if (!ef->writes_pending)
780 return EET_ERROR_NONE;
784 ret = eet_flush2(ef);
797 * We need to compute the list of eet file to close separately from the cache,
798 * due to eet_close removing them from the cache after each call.
801 for (i = 0; i < eet_writers_num; i++)
803 if (eet_writers[i]->references <= 0)
807 for (i = 0; i < eet_readers_num; i++)
809 if (eet_readers[i]->references <= 0)
815 Eet_File **closelist = NULL;
817 closelist = alloca(num * sizeof(Eet_File *));
819 for (i = 0; i < eet_writers_num; i++)
821 if (eet_writers[i]->references <= 0)
823 closelist[num] = eet_writers[i];
824 eet_writers[i]->delete_me_now = 1;
829 for (i = 0; i < eet_readers_num; i++)
831 if (eet_readers[i]->references <= 0)
833 closelist[num] = eet_readers[i];
834 eet_readers[i]->delete_me_now = 1;
839 for (i = 0; i < num; i++)
841 eet_internal_close(closelist[i], EINA_TRUE);
846 } /* eet_clearcache */
848 /* FIXME: MMAP race condition in READ_WRITE_MODE */
850 eet_internal_read2(Eet_File *ef)
852 const int *data = (const int *)ef->data;
853 const char *start = (const char *)ef->data;
855 unsigned long int bytes_directory_entries;
856 unsigned long int bytes_dictionary_entries;
857 unsigned long int signature_base_offset;
858 unsigned long int num_directory_entries;
859 unsigned long int num_dictionary_entries;
863 if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef))
868 #define GET_INT(Value, Pointer, Index)\
870 Value = ntohl(*Pointer);\
872 Index += sizeof(int);\
875 /* get entries count and byte count */
876 GET_INT(num_directory_entries, data, idx);
877 /* get dictionary count and byte count */
878 GET_INT(num_dictionary_entries, data, idx);
880 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE *
881 num_directory_entries + EET_FILE2_HEADER_SIZE;
882 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE *
883 num_dictionary_entries;
885 /* we can't have > 0x7fffffff values here - invalid */
886 if (eet_test_close((num_directory_entries > 0x7fffffff), ef))
889 /* we can't have more bytes directory and bytes in dictionaries than the size of the file */
890 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) >
894 /* allocate header */
895 ef->header = calloc(1, sizeof(Eet_File_Header));
896 if (eet_test_close(!ef->header, ef))
899 ef->header->magic = EET_MAGIC_FILE_HEADER;
901 /* allocate directory block in ram */
902 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
903 if (eet_test_close(!ef->header->directory, ef))
906 /* 8 bit hash table (256 buckets) */
907 ef->header->directory->size = 8;
908 /* allocate base hash table */
909 ef->header->directory->nodes =
910 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
911 if (eet_test_close(!ef->header->directory->nodes, ef))
914 signature_base_offset = 0;
915 if (num_directory_entries == 0)
917 signature_base_offset = ef->data_size;
920 /* actually read the directory block - all of it, into ram */
921 for (i = 0; i < num_directory_entries; ++i)
925 unsigned long int name_offset;
926 unsigned long int name_size;
930 /* out directory block is inconsistent - we have overrun our */
931 /* dynamic block buffer before we finished scanning dir entries */
932 efn = malloc(sizeof(Eet_File_Node));
933 if (eet_test_close(!efn, ef))
935 if (efn) free(efn); /* yes i know - we only get here if
936 * efn is null/0 -> trying to shut up
937 * warning tools like cppcheck */
941 /* get entrie header */
942 GET_INT(efn->offset, data, idx);
943 GET_INT(efn->size, data, idx);
944 GET_INT(efn->data_size, data, idx);
945 GET_INT(name_offset, data, idx);
946 GET_INT(name_size, data, idx);
947 GET_INT(flag, data, idx);
949 efn->compression = flag & 0x1 ? 1 : 0;
950 efn->ciphered = flag & 0x2 ? 1 : 0;
951 efn->alias = flag & 0x4 ? 1 : 0;
953 #define EFN_TEST(Test, Ef, Efn)\
954 if (eet_test_close(Test, Ef))\
960 /* check data pointer position */
961 EFN_TEST(!((efn->size > 0)
962 && (efn->offset + efn->size <= ef->data_size)
963 && (efn->offset > bytes_dictionary_entries +
964 bytes_directory_entries)), ef, efn);
966 /* check name position */
967 EFN_TEST(!((name_size > 0)
968 && (name_offset + name_size < ef->data_size)
969 && (name_offset >= bytes_dictionary_entries +
970 bytes_directory_entries)), ef, efn);
972 name = start + name_offset;
974 /* check '\0' at the end of name string */
975 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
978 efn->name = (char *)name;
979 efn->name_size = name_size;
981 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
982 efn->next = ef->header->directory->nodes[hash];
983 ef->header->directory->nodes[hash] = efn;
985 /* read-only mode, so currently we have no data loaded */
986 if (ef->mode == EET_FILE_MODE_READ)
987 efn->data = NULL; /* read-write mode - read everything into ram */
990 efn->data = malloc(efn->size);
992 memcpy(efn->data, ef->data + efn->offset, efn->size);
995 /* compute the possible position of a signature */
996 if (signature_base_offset < efn->offset + efn->size)
997 signature_base_offset = efn->offset + efn->size;
1002 if (num_dictionary_entries)
1004 const int *dico = (const int *)ef->data +
1005 EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries +
1006 EET_FILE2_HEADER_COUNT;
1009 if (eet_test_close((num_dictionary_entries *
1010 (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) >
1011 (bytes_dictionary_entries + bytes_directory_entries),
1015 ef->ed = calloc(1, sizeof (Eet_Dictionary));
1016 if (eet_test_close(!ef->ed, ef))
1019 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
1020 if (eet_test_close(!ef->ed->all, ef))
1023 ef->ed->count = num_dictionary_entries;
1024 ef->ed->total = num_dictionary_entries;
1025 ef->ed->start = start + bytes_dictionary_entries +
1026 bytes_directory_entries;
1027 ef->ed->end = ef->ed->start;
1029 for (j = 0; j < ef->ed->count; ++j)
1031 unsigned int offset;
1034 GET_INT(hash, dico, idx);
1035 GET_INT(offset, dico, idx);
1036 GET_INT(ef->ed->all[j].len, dico, idx);
1037 GET_INT(ef->ed->all[j].prev, dico, idx);
1038 GET_INT(ef->ed->all[j].next, dico, idx);
1040 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
1041 So stick to int and check the value. */
1042 if (eet_test_close(hash & 0xFFFFFF00, ef))
1045 /* Check string position */
1046 if (eet_test_close(!((ef->ed->all[j].len > 0)
1048 (bytes_dictionary_entries +
1049 bytes_directory_entries))
1050 && (offset + ef->ed->all[j].len <
1051 ef->data_size)), ef))
1054 ef->ed->all[j].str = start + offset;
1056 if (ef->ed->all[j].str + ef->ed->all[j].len > ef->ed->end)
1057 ef->ed->end = ef->ed->all[j].str + ef->ed->all[j].len;
1059 /* Check '\0' at the end of the string */
1060 if (eet_test_close(ef->ed->all[j].str[ef->ed->all[j].len - 1] !=
1064 ef->ed->all[j].hash = hash;
1065 if (ef->ed->all[j].prev == -1)
1066 ef->ed->hash[hash] = j;
1068 /* compute the possible position of a signature */
1069 if (signature_base_offset < offset + ef->ed->all[j].len)
1070 signature_base_offset = offset + ef->ed->all[j].len;
1074 /* Check if the file is signed */
1075 ef->x509_der = NULL;
1076 ef->x509_length = 0;
1077 ef->signature = NULL;
1078 ef->signature_length = 0;
1080 if (signature_base_offset < ef->data_size)
1082 #ifdef HAVE_SIGNATURE
1083 const unsigned char *buffer = ((const unsigned char *)ef->data) +
1084 signature_base_offset;
1085 ef->x509_der = eet_identity_check(ef->data,
1086 signature_base_offset,
1090 ef->data_size - signature_base_offset,
1092 &ef->signature_length,
1095 if (eet_test_close(!ef->x509_der, ef))
1098 #else /* ifdef HAVE_SIGNATURE */
1100 "This file could be signed but you didn't compile the necessary code to check the signature.");
1101 #endif /* ifdef HAVE_SIGNATURE */
1105 } /* eet_internal_read2 */
1107 #if EET_OLD_EET_FILE_FORMAT
1109 eet_internal_read1(Eet_File *ef)
1111 const unsigned char *dyn_buf = NULL;
1112 const unsigned char *p = NULL;
1113 unsigned long int byte_entries;
1114 unsigned long int num_entries;
1119 "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.",
1122 /* build header table if read mode */
1125 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1128 #define EXTRACT_INT(Value, Pointer, Index)\
1131 memcpy(&tmp, Pointer + Index, sizeof(int));\
1132 Value = ntohl(tmp);\
1133 Index += sizeof(int);\
1136 /* get entries count and byte count */
1137 EXTRACT_INT(num_entries, ef->data, idx);
1138 EXTRACT_INT(byte_entries, ef->data, idx);
1140 /* we can't have <= 0 values here - invalid */
1141 if (eet_test_close((num_entries > 0x7fffffff) ||
1142 (byte_entries > 0x7fffffff), ef))
1145 /* we can't have more entires than minimum bytes for those! invalid! */
1146 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1149 /* check we will not outrun the file limit */
1150 if (eet_test_close(((byte_entries + (int)(sizeof(int) * 3)) >
1151 ef->data_size), ef))
1154 /* allocate header */
1155 ef->header = calloc(1, sizeof(Eet_File_Header));
1156 if (eet_test_close(!ef->header, ef))
1159 ef->header->magic = EET_MAGIC_FILE_HEADER;
1161 /* allocate directory block in ram */
1162 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1163 if (eet_test_close(!ef->header->directory, ef))
1166 /* 8 bit hash table (256 buckets) */
1167 ef->header->directory->size = 8;
1168 /* allocate base hash table */
1169 ef->header->directory->nodes =
1170 calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1171 if (eet_test_close(!ef->header->directory->nodes, ef))
1174 /* actually read the directory block - all of it, into ram */
1175 dyn_buf = ef->data + idx;
1177 /* parse directory block */
1180 for (i = 0; i < num_entries; i++)
1189 #define HEADER_SIZE (sizeof(int) * 5)
1191 /* out directory block is inconsistent - we have overrun our */
1192 /* dynamic block buffer before we finished scanning dir entries */
1193 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1196 /* allocate all the ram needed for this stored node accounting */
1197 efn = malloc (sizeof(Eet_File_Node));
1198 if (eet_test_close(!efn, ef))
1200 if (efn) free(efn); /* yes i know - we only get here if
1201 * efn is null/0 -> trying to shut up
1202 * warning tools like cppcheck */
1206 /* get entrie header */
1207 EXTRACT_INT(efn->offset, p, indexn);
1208 EXTRACT_INT(efn->compression, p, indexn);
1209 EXTRACT_INT(efn->size, p, indexn);
1210 EXTRACT_INT(efn->data_size, p, indexn);
1211 EXTRACT_INT(name_size, p, indexn);
1213 efn->name_size = name_size;
1218 if (eet_test_close(efn->size <= 0, ef))
1224 /* invalid name_size */
1225 if (eet_test_close(name_size <= 0, ef))
1231 /* reading name would mean falling off end of dyn_buf - invalid */
1232 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1238 /* This code is useless if we dont want backward compatibility */
1240 k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k)
1243 efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0;
1247 efn->name = malloc(sizeof(char) * name_size + 1);
1248 if (eet_test_close(!efn->name, ef))
1254 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1255 efn->name[name_size] = 0;
1258 "File: %s is not up to date for key \"%s\" - needs rebuilding sometime",
1263 /* The only really useful peace of code for efn->name (no backward compatibility) */
1264 efn->name = (char *)((unsigned char *)(p + HEADER_SIZE));
1266 /* get hash bucket it should go in */
1267 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1268 efn->next = ef->header->directory->nodes[hash];
1269 ef->header->directory->nodes[hash] = efn;
1271 /* read-only mode, so currently we have no data loaded */
1272 if (ef->mode == EET_FILE_MODE_READ)
1273 efn->data = NULL; /* read-write mode - read everything into ram */
1276 data = malloc(efn->size);
1278 memcpy(data, ef->data + efn->offset, efn->size);
1284 p += HEADER_SIZE + name_size;
1287 } /* eet_internal_read1 */
1289 #endif /* if EET_OLD_EET_FILE_FORMAT */
1292 * this should only be called when the cache lock is already held
1293 * (We could drop this restriction if we add a parameter to eet_test_close
1294 * that indicates if the lock is held or not. For now it is easiest
1295 * to just require that it is always held.)
1298 eet_internal_read(Eet_File *ef)
1300 const int *data = (const int *)ef->data;
1302 if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef))
1305 if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef))
1308 switch (ntohl(*data))
1310 #if EET_OLD_EET_FILE_FORMAT
1311 case EET_MAGIC_FILE:
1312 return eet_internal_read1(ef);
1314 #endif /* if EET_OLD_EET_FILE_FORMAT */
1315 case EET_MAGIC_FILE2:
1316 return eet_internal_read2(ef);
1319 ef->delete_me_now = 1;
1320 eet_internal_close(ef, EINA_TRUE);
1325 } /* eet_internal_read */
1328 eet_internal_close(Eet_File *ef,
1333 /* check to see its' an eet file pointer */
1334 if (eet_check_pointer(ef))
1335 return EET_ERROR_BAD_OBJECT;
1342 /* if its still referenced - dont go any further */
1343 if (ef->references > 0)
1345 /* flush any writes */
1346 if ((ef->mode == EET_FILE_MODE_WRITE) ||
1347 (ef->mode == EET_FILE_MODE_READ_WRITE))
1352 err = eet_flush2(ef);
1354 eet_identity_unref(ef->key);
1357 /* if not urgent to delete it - dont free it - leave it in cache */
1358 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1361 /* remove from cache */
1362 if (ef->mode == EET_FILE_MODE_READ)
1363 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1364 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1365 (ef->mode == EET_FILE_MODE_READ_WRITE))
1366 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1368 /* we can unlock the cache now */
1377 if (ef->header->directory)
1379 if (ef->header->directory->nodes)
1383 num = (1 << ef->header->directory->size);
1384 for (i = 0; i < num; i++)
1388 while ((efn = ef->header->directory->nodes[i]))
1393 ef->header->directory->nodes[i] = efn->next;
1401 free(ef->header->directory->nodes);
1404 free(ef->header->directory);
1410 eet_dictionary_free(ef->ed);
1418 eina_file_map_free(ef->readfp, (void *) ef->data);
1420 eina_file_close(ef->readfp);
1423 /* zero out ram for struct - caution tactic against stale memory use */
1424 memset(ef, 0, sizeof(Eet_File));
1434 return EET_ERROR_NONE;
1435 } /* eet_internal_close */
1438 eet_memopen_read(const void *data,
1443 if (!data || size == 0)
1446 ef = malloc (sizeof (Eet_File));
1454 ef->magic = EET_MAGIC_FILE;
1456 ef->mode = EET_FILE_MODE_READ;
1458 ef->delete_me_now = 1;
1461 ef->data_size = size;
1463 ef->sha1_length = 0;
1465 /* eet_internal_read expects the cache lock to be held when it is called */
1467 ef = eet_internal_read(ef);
1470 } /* eet_memopen_read */
1473 eet_open(const char *file,
1479 unsigned long int size;
1484 /* find the current file handle in cache*/
1487 if (mode == EET_FILE_MODE_READ)
1489 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1494 ef->delete_me_now = 1;
1495 eet_internal_close(ef, EINA_TRUE);
1498 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1500 else if ((mode == EET_FILE_MODE_WRITE) ||
1501 (mode == EET_FILE_MODE_READ_WRITE))
1503 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1506 ef->delete_me_now = 1;
1508 eet_internal_close(ef, EINA_TRUE);
1511 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1514 /* try open the file based on mode */
1515 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1517 /* Prevent garbage in futur comparison. */
1518 fp = eina_file_open(file, EINA_FALSE);
1522 size = eina_file_size_get(fp);
1524 if (size < ((int)sizeof(int) * 3))
1526 eina_file_close(fp);
1535 if (!fp && mode == EET_FILE_MODE_READ)
1540 if (mode != EET_FILE_MODE_WRITE)
1549 if (ef && ef->readfp != fp)
1551 ef->delete_me_now = 1;
1553 eet_internal_close(ef, EINA_TRUE);
1559 /* reference it up and return it */
1561 eina_file_close(fp);
1568 file_len = strlen(file) + 1;
1570 /* Allocate struct for eet file and have it zero'd out */
1571 ef = malloc(sizeof(Eet_File) + file_len);
1575 /* fill some of the members */
1579 ef->path = ((char *)ef) + sizeof(Eet_File);
1580 memcpy(ef->path, file, file_len);
1581 ef->magic = EET_MAGIC_FILE;
1585 ef->writes_pending = 0;
1586 ef->delete_me_now = 0;
1590 ef->sha1_length = 0;
1592 ef->ed = (mode == EET_FILE_MODE_WRITE)
1593 || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ?
1594 eet_dictionary_add() : NULL;
1597 (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE))
1600 /* if we can't open - bail out */
1601 if (eet_test_close(!ef->readfp, ef))
1604 /* if we opened for read or read-write */
1605 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1607 ef->data_size = size;
1608 ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL);
1609 if (eet_test_close((ef->data == NULL), ef))
1612 ef = eet_internal_read(ef);
1619 if (ef->references == 1)
1621 if (ef->mode == EET_FILE_MODE_READ)
1622 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1623 else if ((ef->mode == EET_FILE_MODE_WRITE) ||
1624 (ef->mode == EET_FILE_MODE_READ_WRITE))
1625 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1637 eet_mode_get(Eet_File *ef)
1639 /* check to see its' an eet file pointer */
1640 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1641 return EET_FILE_MODE_INVALID;
1644 } /* eet_mode_get */
1647 eet_identity_x509(Eet_File *ef,
1654 *der_length = ef->x509_length;
1656 return ef->x509_der;
1657 } /* eet_identity_x509 */
1660 eet_identity_signature(Eet_File *ef,
1661 int *signature_length)
1666 if (signature_length)
1667 *signature_length = ef->signature_length;
1669 return ef->signature;
1670 } /* eet_identity_signature */
1673 eet_identity_sha1(Eet_File *ef,
1677 ef->sha1 = eet_identity_compute_sha1(ef->data,
1682 *sha1_length = ef->sha1_length;
1685 } /* eet_identity_sha1 */
1688 eet_identity_set(Eet_File *ef,
1694 return EET_ERROR_BAD_OBJECT;
1698 eet_identity_ref(ef->key);
1699 eet_identity_unref(tmp);
1701 /* flags that writes are pending */
1702 ef->writes_pending = 1;
1704 return EET_ERROR_NONE;
1705 } /* eet_identity_set */
1708 eet_close(Eet_File *ef)
1710 return eet_internal_close(ef, EINA_FALSE);
1714 eet_read_cipher(Eet_File *ef,
1717 const char *cipher_key)
1721 unsigned long int size = 0;
1726 /* check to see its' an eet file pointer */
1727 if (eet_check_pointer(ef))
1733 if ((ef->mode != EET_FILE_MODE_READ) &&
1734 (ef->mode != EET_FILE_MODE_READ_WRITE))
1737 /* no header, return NULL */
1738 if (eet_check_header(ef))
1743 /* hunt hash bucket */
1744 efn = find_node_by_name(ef, name);
1748 /* get size (uncompressed, if compressed at all) */
1749 size = efn->data_size;
1752 data = malloc(size);
1756 /* uncompressed data */
1757 if (efn->compression == 0)
1759 void *data_deciphered = NULL;
1760 unsigned int data_deciphered_sz = 0;
1761 /* if we already have the data in ram... copy that */
1763 if (efn->ciphered && efn->size > size)
1766 data = realloc(data, efn->size);
1770 memcpy(data, efn->data, size);
1772 if (!read_data_from_disk(ef, efn, data, size))
1775 if (efn->ciphered && cipher_key)
1777 if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key),
1778 &data_deciphered, &data_deciphered_sz))
1780 if (data_deciphered)
1781 free(data_deciphered);
1787 data = data_deciphered;
1788 size = data_deciphered_sz;
1791 /* compressed data */
1794 void *tmp_data = NULL;
1795 void *data_deciphered = NULL;
1796 unsigned int data_deciphered_sz = 0;
1798 int compr_size = efn->size;
1801 /* if we already have the data in ram... copy that */
1803 tmp_data = efn->data;
1806 tmp_data = malloc(compr_size);
1812 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1819 if (efn->ciphered && cipher_key)
1821 if (eet_decipher(tmp_data, compr_size, cipher_key,
1822 strlen(cipher_key), &data_deciphered,
1823 &data_deciphered_sz))
1828 if (data_deciphered)
1829 free(data_deciphered);
1837 tmp_data = data_deciphered;
1838 compr_size = data_deciphered_sz;
1843 if (uncompress((Bytef *)data, &dlen,
1844 tmp_data, (uLongf)compr_size))
1862 if (data[size - 1] != '\0')
1865 tmp = eet_read_cipher(ef, data, size_ret, cipher_key);
1872 /* fill in return values */
1882 } /* eet_read_cipher */
1885 eet_read(Eet_File *ef,
1889 return eet_read_cipher(ef, name, size_ret, NULL);
1893 eet_read_direct(Eet_File *ef,
1898 const char *data = NULL;
1904 /* check to see its' an eet file pointer */
1905 if (eet_check_pointer(ef))
1911 if ((ef->mode != EET_FILE_MODE_READ) &&
1912 (ef->mode != EET_FILE_MODE_READ_WRITE))
1915 /* no header, return NULL */
1916 if (eet_check_header(ef))
1921 /* hunt hash bucket */
1922 efn = find_node_by_name(ef, name);
1926 /* trick to detect data in memory instead of mmaped from disk */
1927 if (efn->offset > ef->data_size && !efn->data)
1930 /* get size (uncompressed, if compressed at all) */
1931 size = efn->data_size;
1935 data = efn->data ? efn->data : ef->data + efn->offset;
1937 /* handle alias case */
1938 if (efn->compression)
1941 int compr_size = efn->size;
1944 tmp = alloca(sizeof (compr_size));
1947 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
1948 (uLongf)compr_size))
1951 if (tmp[compr_size - 1] != '\0')
1956 return eet_read_direct(ef, tmp, size_ret);
1962 if (data[size - 1] != '\0')
1967 return eet_read_direct(ef, data, size_ret);
1970 /* uncompressed data */
1971 if (efn->compression == 0
1972 && efn->ciphered == 0)
1973 data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */
1977 /* fill in return values */
1988 } /* eet_read_direct */
1991 eet_alias_get(Eet_File *ef,
1995 const char *data = NULL;
1998 /* check to see its' an eet file pointer */
1999 if (eet_check_pointer(ef))
2005 if ((ef->mode != EET_FILE_MODE_READ) &&
2006 (ef->mode != EET_FILE_MODE_READ_WRITE))
2009 /* no header, return NULL */
2010 if (eet_check_header(ef))
2015 /* hunt hash bucket */
2016 efn = find_node_by_name(ef, name);
2020 /* trick to detect data in memory instead of mmaped from disk */
2021 if (efn->offset > ef->data_size && !efn->data)
2024 /* get size (uncompressed, if compressed at all) */
2025 size = efn->data_size;
2027 if (!efn->alias) return NULL;
2028 data = efn->data ? efn->data : ef->data + efn->offset;
2030 /* handle alias case */
2031 if (efn->compression)
2034 int compr_size = efn->size;
2037 tmp = alloca(sizeof (compr_size));
2040 if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data,
2041 (uLongf)compr_size))
2044 if (tmp[compr_size - 1] != '\0')
2049 return eina_stringshare_add(tmp);
2055 if (data[size - 1] != '\0')
2060 return eina_stringshare_add(data);
2068 eet_alias(Eet_File *ef,
2070 const char *destination,
2075 Eina_Bool exists_already = EINA_FALSE;
2079 /* check to see its' an eet file pointer */
2080 if (eet_check_pointer(ef))
2083 if ((!name) || (!destination))
2086 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2087 (ef->mode != EET_FILE_MODE_READ_WRITE))
2094 /* allocate header */
2095 ef->header = calloc(1, sizeof(Eet_File_Header));
2099 ef->header->magic = EET_MAGIC_FILE_HEADER;
2100 /* allocate directory block in ram */
2101 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2102 if (!ef->header->directory)
2109 /* 8 bit hash table (256 buckets) */
2110 ef->header->directory->size = 8;
2111 /* allocate base hash table */
2112 ef->header->directory->nodes =
2113 calloc(1, sizeof(Eet_File_Node *) *
2114 (1 << ef->header->directory->size));
2115 if (!ef->header->directory->nodes)
2117 free(ef->header->directory);
2123 /* figure hash bucket */
2124 hash = _eet_hash_gen(name, ef->header->directory->size);
2127 12 + (((strlen(destination) + 1) * 101) / 100)
2128 : strlen(destination) + 1;
2130 data2 = malloc(data_size);
2134 /* if we want to compress */
2139 /* compress the data with max compression */
2140 buflen = (uLongf)data_size;
2141 if (compress2((Bytef *)data2, &buflen, (Bytef *)destination,
2142 (uLong)strlen(destination) + 1,
2143 Z_BEST_COMPRESSION) != Z_OK)
2149 /* record compressed chunk size */
2150 data_size = (int)buflen;
2151 if (data_size < 0 || data_size >= (int)(strlen(destination) + 1))
2154 data_size = strlen(destination) + 1;
2160 data3 = realloc(data2, data_size);
2167 memcpy(data2, destination, data_size);
2169 /* Does this node already exist? */
2170 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2173 if ((efn->name) && (eet_string_match(efn->name, name)))
2178 efn->compression = !!comp;
2179 efn->size = data_size;
2180 efn->data_size = strlen(destination) + 1;
2182 /* Put the offset above the limit to avoid direct access */
2183 efn->offset = ef->data_size + 1;
2184 exists_already = EINA_TRUE;
2189 if (!exists_already)
2191 efn = malloc(sizeof(Eet_File_Node));
2198 efn->name = strdup(name);
2199 efn->name_size = strlen(efn->name) + 1;
2202 efn->next = ef->header->directory->nodes[hash];
2203 ef->header->directory->nodes[hash] = efn;
2204 /* Put the offset above the limit to avoid direct access */
2205 efn->offset = ef->data_size + 1;
2208 efn->compression = !!comp;
2209 efn->size = data_size;
2210 efn->data_size = strlen(destination) + 1;
2214 /* flags that writes are pending */
2215 ef->writes_pending = 1;
2226 eet_write_cipher(Eet_File *ef,
2231 const char *cipher_key)
2235 int exists_already = 0;
2239 /* check to see its' an eet file pointer */
2240 if (eet_check_pointer(ef))
2243 if ((!name) || (!data) || (size <= 0))
2246 if ((ef->mode != EET_FILE_MODE_WRITE) &&
2247 (ef->mode != EET_FILE_MODE_READ_WRITE))
2254 /* allocate header */
2255 ef->header = calloc(1, sizeof(Eet_File_Header));
2259 ef->header->magic = EET_MAGIC_FILE_HEADER;
2260 /* allocate directory block in ram */
2261 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
2262 if (!ef->header->directory)
2269 /* 8 bit hash table (256 buckets) */
2270 ef->header->directory->size = 8;
2271 /* allocate base hash table */
2272 ef->header->directory->nodes =
2273 calloc(1, sizeof(Eet_File_Node *) *
2274 (1 << ef->header->directory->size));
2275 if (!ef->header->directory->nodes)
2277 free(ef->header->directory);
2283 /* figure hash bucket */
2284 hash = _eet_hash_gen(name, ef->header->directory->size);
2286 data_size = comp ? 12 + ((size * 101) / 100) : size;
2288 if (comp || !cipher_key)
2290 data2 = malloc(data_size);
2295 /* if we want to compress */
2300 /* compress the data with max compression */
2301 buflen = (uLongf)data_size;
2302 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
2303 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
2309 /* record compressed chunk size */
2310 data_size = (int)buflen;
2311 if (data_size < 0 || data_size >= size)
2320 data3 = realloc(data2, data_size);
2328 void *data_ciphered = NULL;
2329 unsigned int data_ciphered_sz = 0;
2332 tmp = comp ? data2 : data;
2333 if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key),
2334 &data_ciphered, &data_ciphered_sz))
2339 data2 = data_ciphered;
2340 data_size = data_ciphered_sz;
2345 free(data_ciphered);
2352 memcpy(data2, data, size);
2354 /* Does this node already exist? */
2355 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2358 if ((efn->name) && (eet_string_match(efn->name, name)))
2362 efn->ciphered = cipher_key ? 1 : 0;
2363 efn->compression = !!comp;
2364 efn->size = data_size;
2365 efn->data_size = size;
2367 /* Put the offset above the limit to avoid direct access */
2368 efn->offset = ef->data_size + 1;
2373 if (!exists_already)
2375 efn = malloc(sizeof(Eet_File_Node));
2382 efn->name = strdup(name);
2383 efn->name_size = strlen(efn->name) + 1;
2386 efn->next = ef->header->directory->nodes[hash];
2387 ef->header->directory->nodes[hash] = efn;
2388 /* Put the offset above the limit to avoid direct access */
2389 efn->offset = ef->data_size + 1;
2391 efn->ciphered = cipher_key ? 1 : 0;
2392 efn->compression = !!comp;
2393 efn->size = data_size;
2394 efn->data_size = size;
2398 /* flags that writes are pending */
2399 ef->writes_pending = 1;
2406 } /* eet_write_cipher */
2409 eet_write(Eet_File *ef,
2415 return eet_write_cipher(ef, name, data, size, comp, NULL);
2419 eet_delete(Eet_File *ef,
2423 Eet_File_Node *pefn;
2425 int exists_already = 0;
2427 /* check to see its' an eet file pointer */
2428 if (eet_check_pointer(ef))
2434 /* deleting keys is only possible in RW or WRITE mode */
2435 if (ef->mode == EET_FILE_MODE_READ)
2438 if (eet_check_header(ef))
2443 /* figure hash bucket */
2444 hash = _eet_hash_gen(name, ef->header->directory->size);
2446 /* Does this node already exist? */
2447 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
2449 pefn = efn, efn = efn->next)
2452 if (eet_string_match(efn->name, name))
2458 ef->header->directory->nodes[hash] = efn->next;
2460 pefn->next = efn->next;
2470 /* flags that writes are pending */
2472 ef->writes_pending = 1;
2476 /* update access time */
2477 return exists_already;
2480 EAPI Eet_Dictionary *
2481 eet_dictionary_get(Eet_File *ef)
2483 if (eet_check_pointer(ef))
2487 } /* eet_dictionary_get */
2490 eet_list(Eet_File *ef,
2495 char **list_ret = NULL;
2497 int list_count_alloc = 0;
2500 /* check to see its' an eet file pointer */
2501 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2503 ((ef->mode != EET_FILE_MODE_READ) &&
2504 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2512 if (!strcmp(glob, "*"))
2517 /* loop through all entries */
2518 num = (1 << ef->header->directory->size);
2519 for (i = 0; i < num; i++)
2521 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2523 /* if the entry matches the input glob
2524 * check for * explicitly, because on some systems, * isn't well
2527 if ((!glob) || !fnmatch(glob, efn->name, 0))
2529 /* add it to our list */
2532 /* only realloc in 32 entry chunks */
2533 if (list_count > list_count_alloc)
2535 char **new_list = NULL;
2537 list_count_alloc += 64;
2539 realloc(list_ret, list_count_alloc * (sizeof(char *)));
2547 list_ret = new_list;
2550 /* put pointer of name string in */
2551 list_ret[list_count - 1] = efn->name;
2558 /* return count and list */
2560 *count_ret = list_count;
2574 eet_num_entries(Eet_File *ef)
2576 int i, num, ret = 0;
2579 /* check to see its' an eet file pointer */
2580 if (eet_check_pointer(ef) || eet_check_header(ef) ||
2581 ((ef->mode != EET_FILE_MODE_READ) &&
2582 (ef->mode != EET_FILE_MODE_READ_WRITE)))
2587 /* loop through all entries */
2588 num = (1 << ef->header->directory->size);
2589 for (i = 0; i < num; i++)
2591 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
2598 } /* eet_num_entries */
2600 static Eet_File_Node *
2601 find_node_by_name(Eet_File *ef,
2607 /* get hash bucket this should be in */
2608 hash = _eet_hash_gen(name, ef->header->directory->size);
2610 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
2612 if (eet_string_match(efn->name, name))
2617 } /* find_node_by_name */
2620 read_data_from_disk(Eet_File *ef,
2625 if (efn->offset > ef->data_size)
2631 if ((efn->offset + len) > ef->data_size)
2634 memcpy(buf, ef->data + efn->offset, len);
2637 } /* read_data_from_disk */