2 * vim:ts=8:sw=3:sts=8:noexpandtab:cino=>5n-3f0^-2{2
11 #elif defined __GNUC__
12 # define alloca __builtin_alloca
14 # define alloca __alloca
15 #elif defined _MSC_VER
17 # define alloca _alloca
23 void *alloca (size_t);
28 #include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
42 #if defined(_WIN32) && ! defined(__CEGCC__)
43 # include <winsock2.h>
51 #include "Eet_private.h"
57 #define EET_MAGIC_FILE 0x1ee7ff00
58 #define EET_MAGIC_FILE_HEADER 0x1ee7ff01
60 #define EET_MAGIC_FILE2 0x1ee70f42
62 typedef struct _Eet_File_Header Eet_File_Header;
63 typedef struct _Eet_File_Node Eet_File_Node;
64 typedef struct _Eet_File_Directory Eet_File_Directory;
71 Eet_File_Header *header;
74 const unsigned char *data;
85 unsigned char writes_pending : 1;
86 unsigned char delete_me_now : 1;
89 struct _Eet_File_Header
92 Eet_File_Directory *directory;
95 struct _Eet_File_Directory
98 Eet_File_Node **nodes;
101 struct _Eet_File_Node
105 Eet_File_Node *next; /* FIXME: make buckets linked lists */
108 int dictionary_offset;
115 unsigned char free_name : 1;
116 unsigned char compression : 1;
121 /* NB: all int's are stored in network byte order on disk */
123 int magic; /* magic number ie 0x1ee7ff00 */
124 int num_directory_entries; /* number of directory entries to follow */
125 int bytes_directory_entries; /* bytes of directory entries to follow */
128 int offset; /* bytes offset into file for data chunk */
129 int flags; /* flags - for now 0 = uncompressed, 1 = compressed */
130 int size; /* size of the data chunk */
131 int data_size; /* size of the (uncompressed) data chunk */
132 int name_size; /* length in bytes of the name field */
133 char name[name_size]; /* name string (variable length) and \0 terminated */
134 } directory[num_directory_entries];
135 /* and now startes the data stream... */
140 /* NB: all int's are stored in network byte order on disk */
142 int magic; /* magic number ie 0x1ee70f42 */
143 int num_directory_entries; /* number of directory entries to follow */
144 int num_dictionary_entries; /* number of dictionary entries to follow */
147 int data_offset; /* bytes offset into file for data chunk */
148 int size; /* size of the data chunk */
149 int data_size; /* size of the (uncompressed) data chunk */
150 int name_offset; /* bytes offset into file for name string */
151 int name_size; /* length in bytes of the name field */
152 int flags; /* flags - for now 0 = uncompressed, 1 = compressed */
153 } directory[num_directory_entries];
161 } dictionary[num_dictionary_entries];
162 /* now start the string stream. */
163 /* and right after them the data stream. */
164 int magic_sign; /* Optional, only if the eet file is signed. */
165 int signature_length; /* Signature length. */
166 int x509_length; /* Public certificate that signed the file. */
167 char signature[signature_length]; /* The signature. */
168 char x509[x509_length]; /* The public certificate. */
171 #define EET_FILE2_HEADER_COUNT 3
172 #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6
173 #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5
175 #define EET_FILE2_HEADER_SIZE (sizeof(int) * EET_FILE2_HEADER_COUNT)
176 #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DIRECTORY_ENTRY_COUNT)
177 #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) * EET_FILE2_DICTIONARY_ENTRY_COUNT)
179 /* prototypes of internal calls */
180 static Eet_File *eet_cache_find(const char *path, Eet_File **cache, int cache_num);
181 static void eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
182 static void eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc);
183 static int eet_string_match(const char *s1, const char *s2);
185 static Eet_Error eet_flush(Eet_File *ef);
187 static Eet_Error eet_flush2(Eet_File *ef);
188 static Eet_File_Node *find_node_by_name(Eet_File *ef, const char *name);
189 static int read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len);
191 /* cache. i don't expect this to ever be large, so arrays will do */
192 static int eet_writers_num = 0;
193 static int eet_writers_alloc = 0;
194 static Eet_File **eet_writers = NULL;
195 static int eet_readers_num = 0;
196 static int eet_readers_alloc = 0;
197 static Eet_File **eet_readers = NULL;
198 static int eet_initcount = 0;
200 /* Check to see its' an eet file pointer */
202 eet_check_pointer(const Eet_File *ef)
204 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
210 eet_check_header(const Eet_File *ef)
214 if (!ef->header->directory)
220 eet_test_close(int test, Eet_File *ef)
224 ef->delete_me_now = 1;
230 /* find an eet file in the currently in use cache */
232 eet_cache_find(const char *path, Eet_File **cache, int cache_num)
237 for (i = 0; i < cache_num; i++)
239 /* if matches real path - return it */
240 if (eet_string_match(cache[i]->path, path))
242 if (!cache[i]->delete_me_now)
251 /* add to end of cache */
253 eet_cache_add(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
255 Eet_File **new_cache;
259 new_cache_num = *cache_num;
260 if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */
262 Eet_File *del_ef = NULL;
266 for (i = 0; i < new_cache_num; i++)
268 if (new_cache[i]->references == 0)
270 del_ef = new_cache[i];
277 del_ef->delete_me_now = 1;
283 new_cache_num = *cache_num;
284 new_cache_alloc = *cache_alloc;
286 if (new_cache_num > new_cache_alloc)
288 new_cache_alloc += 16;
289 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
292 fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n");
296 new_cache[new_cache_num - 1] = ef;
298 *cache_num = new_cache_num;
299 *cache_alloc = new_cache_alloc;
302 /* delete from cache */
304 eet_cache_del(Eet_File *ef, Eet_File ***cache, int *cache_num, int *cache_alloc)
306 Eet_File **new_cache;
307 int new_cache_num, new_cache_alloc;
311 new_cache_num = *cache_num;
312 new_cache_alloc = *cache_alloc;
313 if (new_cache_num <= 0)
316 for (i = 0; i < new_cache_num; i++)
318 if (new_cache[i] == ef)
322 if (i >= new_cache_num)
326 for (j = i; j < new_cache_num; j++)
327 new_cache[j] = new_cache[j + 1];
329 if (new_cache_num <= (new_cache_alloc - 16))
331 new_cache_alloc -= 16;
332 if (new_cache_num > 0)
334 new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *));
337 fprintf(stderr, "BAD ERROR! Eet realloc of cache list failed. Abort\n");
348 *cache_num = new_cache_num;
349 *cache_alloc = new_cache_alloc;
352 /* internal string match. null friendly, catches same ptr */
354 eet_string_match(const char *s1, const char *s2)
356 /* both null- no match */
357 if ((!s1) || (!s2)) return 0;
358 if (s1 == s2) return 1;
359 return (!strcmp(s1, s2));
362 /* flush out writes to a v2 eet file */
364 eet_flush2(Eet_File *ef)
367 Eet_Error error = EET_ERROR_NONE;
368 int head[EET_FILE2_HEADER_COUNT];
369 int num_directory_entries = 0;
370 int num_dictionary_entries = 0;
371 int bytes_directory_entries = 0;
372 int bytes_dictionary_entries = 0;
373 int bytes_strings = 0;
375 int strings_offset = 0;
380 if (eet_check_pointer(ef))
381 return EET_ERROR_BAD_OBJECT;
382 if (eet_check_header(ef))
383 return EET_ERROR_EMPTY;
384 if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE))
385 return EET_ERROR_NOT_WRITABLE;
386 if (!ef->writes_pending)
387 return EET_ERROR_NONE;
388 if (ef->mode == EET_FILE_MODE_READ_WRITE && ef->fp == NULL)
393 fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR);
394 ef->fp = fdopen(fd, "wb");
395 if (!ef->fp) return EET_ERROR_NOT_WRITABLE;
396 fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC);
399 /* calculate string base offset and data base offset */
400 num = (1 << ef->header->directory->size);
401 for (i = 0; i < num; ++i)
403 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
405 num_directory_entries++;
406 bytes_strings += strlen(efn->name) + 1;
411 num_dictionary_entries = ef->ed->count;
413 for (i = 0; i < num_dictionary_entries; ++i)
414 bytes_strings += ef->ed->all[i].len;
417 /* calculate section bytes size */
418 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
419 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
421 /* calculate per entry offset */
422 strings_offset = bytes_directory_entries + bytes_dictionary_entries;
423 data_offset = bytes_directory_entries + bytes_dictionary_entries + bytes_strings;
425 for (i = 0; i < num; ++i)
427 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
429 efn->offset = data_offset;
430 data_offset += efn->size;
432 efn->name_offset = strings_offset;
433 strings_offset += efn->name_size;
437 /* calculate dictionary strings offset */
439 ef->ed->offset = strings_offset;
441 /* go thru and write the header */
442 head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE2);
443 head[1] = (int) htonl ((unsigned int) num_directory_entries);
444 head[2] = (int) htonl ((unsigned int) num_dictionary_entries);
446 fseek(ef->fp, 0, SEEK_SET);
447 if (fwrite(head, sizeof (head), 1, ef->fp) != 1)
450 /* write directories entry */
452 for (i = 0; i < num; i++)
454 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
456 int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT];
458 ibuf[0] = (int) htonl ((unsigned int) efn->offset);
459 ibuf[1] = (int) htonl ((unsigned int) efn->size);
460 ibuf[2] = (int) htonl ((unsigned int) efn->data_size);
461 ibuf[3] = (int) htonl ((unsigned int) efn->name_offset);
462 ibuf[4] = (int) htonl ((unsigned int) efn->name_size);
463 ibuf[5] = (int) htonl ((unsigned int) efn->compression);
465 if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1)
470 /* write dictionnary */
473 int offset = strings_offset;
475 for (j = 0; j < ef->ed->count; ++j)
477 int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT];
479 sbuf[0] = (int) htonl ((unsigned int) ef->ed->all[j].hash);
480 sbuf[1] = (int) htonl ((unsigned int) offset);
481 sbuf[2] = (int) htonl ((unsigned int) ef->ed->all[j].len);
482 sbuf[3] = (int) htonl ((unsigned int) ef->ed->all[j].prev);
483 sbuf[4] = (int) htonl ((unsigned int) ef->ed->all[j].next);
485 offset += ef->ed->all[j].len;
487 if (fwrite(sbuf, sizeof (sbuf), 1, ef->fp) != 1)
492 /* write directories name */
493 for (i = 0; i < num; i++)
495 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
497 if (fwrite(efn->name, efn->name_size, 1, ef->fp) != 1)
505 for (j = 0; j < ef->ed->count; ++j)
507 if (ef->ed->all[j].str)
509 if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, ef->fp) != 1)
514 if (fwrite(ef->ed->all[j].mmap, ef->ed->all[j].len, 1, ef->fp) != 1)
521 for (i = 0; i < num; i++)
523 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
525 if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
530 /* flush all write to the file. */
533 /* append signature if required */
536 error = eet_identity_sign(ef->fp, ef->key);
537 if (error != EET_ERROR_NONE)
541 /* no more writes pending */
542 ef->writes_pending = 0;
544 return EET_ERROR_NONE;
547 switch (ferror(ef->fp))
549 case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break;
550 case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break;
551 case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break;
552 case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break;
553 default: error = EET_ERROR_WRITE_ERROR; break;
556 if (ef->fp) fclose(ef->fp);
562 /* flush out writes to an eet file */
564 eet_flush(Eet_File *ef)
574 /* check to see its' an eet file pointer */
575 if (eet_check_pointer(ef))
576 return EET_ERROR_BAD_OBJECT;
577 if (eet_check_header(ef))
578 return EET_ERROR_EMPTY;
579 if ((ef->mode != EET_FILE_MODE_WRITE) && (ef->mode != EET_FILE_MODE_READ_WRITE))
580 return EET_ERROR_NOT_WRITABLE;
581 if (!ef->writes_pending)
582 return EET_ERROR_NONE;
584 /* calculate total size in bytes of directory block */
585 num = (1 << ef->header->directory->size);
586 for (i = 0; i < num; i++)
588 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
590 size += 20 + strlen(efn->name) + 1;
595 /* calculate offsets per entry */
597 for (i = 0; i < num; i++)
599 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
601 efn->offset = 12 + size + offset;
606 /* go thru and write the header */
607 head[0] = (int) htonl ((unsigned int) EET_MAGIC_FILE);
608 head[1] = (int) htonl ((unsigned int) count);
609 head[2] = (int) htonl ((unsigned int) size);
611 fseek(ef->fp, 0, SEEK_SET);
612 if (fwrite(head, 12, 1, ef->fp) != 1)
615 for (i = 0; i < num; i++)
617 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
619 unsigned int ibuf[5];
622 name_size = strlen(efn->name) + 1;
624 ibuf[0] = (int) htonl ((unsigned int) efn->offset);
625 ibuf[1] = (int) htonl ((unsigned int) efn->compression);
626 ibuf[2] = (int) htonl ((unsigned int) efn->size);
627 ibuf[3] = (int) htonl ((unsigned int) efn->data_size);
628 ibuf[4] = (int) htonl ((unsigned int) name_size);
631 if (fwrite(ibuf, sizeof(ibuf), 1, ef->fp) != 1)
633 if (fwrite(efn->name, name_size, 1, ef->fp) != 1)
639 for (i = 0; i < num; i++)
641 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
643 if (fwrite(efn->data, efn->size, 1, ef->fp) != 1)
648 /* no more writes pending */
649 ef->writes_pending = 0;
651 return EET_ERROR_NONE;
654 switch (ferror(ef->fp))
659 return EET_ERROR_WRITE_ERROR_FILE_TOO_BIG;
663 return EET_ERROR_WRITE_ERROR_IO_ERROR;
667 return EET_ERROR_WRITE_ERROR_OUT_OF_SPACE;
671 return EET_ERROR_WRITE_ERROR_FILE_CLOSED;
675 return EET_ERROR_WRITE_ERROR;
680 return EET_ERROR_WRITE_ERROR;
688 /* Just load the crypto library error strings,
689 * SSL_load_error_strings() loads the crypto AND the SSL ones */
690 /* SSL_load_error_strings();*/
691 static int call_once = 0;
696 ERR_load_crypto_strings();
700 return ++eet_initcount;
706 if (--eet_initcount == 0)
711 return eet_initcount;
721 * We need to compute the list of eet file to close separately from the cache,
722 * due to eet_close removing them from the cache after each call.
724 for (i = 0; i < eet_writers_num; i++)
726 if (eet_writers[i]->references <= 0) num++;
729 for (i = 0; i < eet_readers_num; i++)
731 if (eet_readers[i]->references <= 0) num++;
736 Eet_File **closelist = NULL;
738 closelist = alloca(num * sizeof(Eet_File *));
740 for (i = 0; i < eet_writers_num; i++)
742 if (eet_writers[i]->references <= 0)
744 closelist[num] = eet_writers[i];
745 eet_writers[i]->delete_me_now = 1;
750 for (i = 0; i < eet_readers_num; i++)
752 if (eet_readers[i]->references <= 0)
754 closelist[num] = eet_readers[i];
755 eet_readers[i]->delete_me_now = 1;
760 for (i = 0; i < num; i++)
762 eet_close(closelist[i]);
767 /* FIXME: MMAP race condition in READ_WRITE_MODE */
769 eet_internal_read2(Eet_File *ef)
771 const int *data = (const int*) ef->data;
772 const char *start = (const char*) ef->data;
774 int num_directory_entries;
775 int bytes_directory_entries;
776 int num_dictionary_entries;
777 int bytes_dictionary_entries;
778 int signature_base_offset;
781 index += sizeof(int);
782 if (eet_test_close((int) ntohl(*data) != EET_MAGIC_FILE2, ef))
786 #define GET_INT(Value, Pointer, Index) \
788 Value = ntohl(*Pointer); \
790 Index += sizeof(int); \
793 /* get entries count and byte count */
794 GET_INT(num_directory_entries, data, index);
795 /* get dictionary count and byte count */
796 GET_INT(num_dictionary_entries, data, index);
798 bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * num_directory_entries + EET_FILE2_HEADER_SIZE;
799 bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * num_dictionary_entries;
801 /* we cant have <= 0 values here - invalid */
802 if (eet_test_close((num_directory_entries <= 0), ef))
805 /* we cant have more bytes directory and bytes in dictionaries than the size of the file */
806 if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) > ef->data_size, ef))
809 /* allocate header */
810 ef->header = calloc(1, sizeof(Eet_File_Header));
811 if (eet_test_close(!ef->header, ef))
814 ef->header->magic = EET_MAGIC_FILE_HEADER;
816 /* allocate directory block in ram */
817 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
818 if (eet_test_close(!ef->header->directory, ef))
821 /* 8 bit hash table (256 buckets) */
822 ef->header->directory->size = 8;
823 /* allocate base hash table */
824 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
825 if (eet_test_close(!ef->header->directory->nodes, ef))
828 signature_base_offset = 0;
830 /* actually read the directory block - all of it, into ram */
831 for (i = 0; i < num_directory_entries; ++i)
839 /* out directory block is inconsistent - we have oveerun our */
840 /* dynamic block buffer before we finished scanning dir entries */
841 efn = malloc (sizeof(Eet_File_Node));
842 if (eet_test_close(!efn, ef))
845 /* get entrie header */
846 GET_INT(efn->offset, data, index);
847 GET_INT(efn->size, data, index);
848 GET_INT(efn->data_size, data, index);
849 GET_INT(name_offset, data, index);
850 GET_INT(name_size, data, index);
851 GET_INT(efn->compression, data, index);
853 #define EFN_TEST(Test, Ef, Efn) \
854 if (eet_test_close(Test, Ef)) \
860 /* check data pointer position */
861 EFN_TEST(!((efn->size > 0)
862 && (efn->offset + efn->size <= ef->data_size)
863 && (efn->offset > bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
865 /* check name position */
866 EFN_TEST(!((name_size > 0)
867 && (name_offset + name_size < ef->data_size)
868 && (name_offset >= bytes_dictionary_entries + bytes_directory_entries)), ef, efn);
870 name = start + name_offset;
872 /* check '\0' at the end of name string */
873 EFN_TEST(name[name_size - 1] != '\0', ef, efn);
876 efn->name = (char*) name;
877 efn->name_size = name_size;
879 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
880 efn->next = ef->header->directory->nodes[hash];
881 ef->header->directory->nodes[hash] = efn;
883 /* read-only mode, so currently we have no data loaded */
884 if (ef->mode == EET_FILE_MODE_READ)
886 /* read-write mode - read everything into ram */
889 efn->data = malloc(efn->size);
891 memcpy(efn->data, ef->data + efn->offset, efn->size);
894 /* compute the possible position of a signature */
895 if (signature_base_offset < efn->offset + efn->size)
896 signature_base_offset = efn->offset + efn->size;
901 if (num_dictionary_entries)
903 const int *dico = (const int*) ef->data + EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries + EET_FILE2_HEADER_COUNT;
906 if (eet_test_close((num_dictionary_entries * EET_FILE2_DICTIONARY_ENTRY_SIZE + index) > (bytes_dictionary_entries + bytes_directory_entries), ef))
909 ef->ed = calloc(1, sizeof (Eet_Dictionary));
910 if (eet_test_close(!ef->ed, ef)) return NULL;
912 ef->ed->all = calloc(num_dictionary_entries, sizeof (Eet_String));
913 if (eet_test_close(!ef->ed->all, ef)) return NULL;
915 ef->ed->count = num_dictionary_entries;
916 ef->ed->total = num_dictionary_entries;
917 ef->ed->start = start + bytes_dictionary_entries + bytes_directory_entries;
918 ef->ed->end = ef->ed->start;
920 for (j = 0; j < ef->ed->count; ++j)
925 GET_INT(hash, dico, index);
926 GET_INT(offset, dico, index);
927 GET_INT(ef->ed->all[j].len, dico, index);
928 GET_INT(ef->ed->all[j].prev, dico, index);
929 GET_INT(ef->ed->all[j].next, dico, index);
931 /* Hash value could be stored on 8bits data, but this will break alignment of all the others data.
932 So stick to int and check the value. */
933 if (eet_test_close(hash & 0xFFFFFF00, ef)) return NULL;
935 /* Check string position */
936 if (eet_test_close(!((ef->ed->all[j].len > 0)
937 && (offset > (bytes_dictionary_entries + bytes_directory_entries))
938 && (offset + ef->ed->all[j].len < ef->data_size)), ef))
941 ef->ed->all[j].mmap = start + offset;
942 ef->ed->all[j].str = NULL;
944 if (ef->ed->all[j].mmap + ef->ed->all[j].len > ef->ed->end)
945 ef->ed->end = ef->ed->all[j].mmap + ef->ed->all[j].len;
947 /* Check '\0' at the end of the string */
948 if (eet_test_close(ef->ed->all[j].mmap[ef->ed->all[j].len - 1] != '\0', ef)) return NULL;
950 ef->ed->all[j].hash = hash;
951 if (ef->ed->all[j].prev == -1)
952 ef->ed->hash[hash] = j;
954 /* compute the possible position of a signature */
955 if (signature_base_offset < offset + ef->ed->all[j].len)
956 signature_base_offset = offset + ef->ed->all[j].len;
960 /* Check if the file is signed */
963 if (signature_base_offset < ef->data_size)
965 #ifdef HAVE_SIGNATURE
966 const unsigned char *buffer = ((const unsigned char*) ef->data) + signature_base_offset;
967 ef->x509_der = eet_identity_check(ef->data, signature_base_offset,
968 buffer, ef->data_size - signature_base_offset,
971 if (ef->x509_der == NULL)
973 ef->delete_me_now = 1;
978 fprintf(stderr, "This file could be signed but you didn't compile the necessary code to check the signature.\n");
985 #if EET_OLD_EET_FILE_FORMAT
987 eet_internal_read1(Eet_File *ef)
989 const unsigned char *dyn_buf = NULL;
990 const unsigned char *p = NULL;
996 fprintf(stderr, "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.\n", ef->path);
998 /* build header table if read mode */
1000 index += sizeof(int);
1001 if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef))
1004 #define EXTRACT_INT(Value, Pointer, Index) \
1007 memcpy(&tmp, Pointer + Index, sizeof(int)); \
1008 Value = ntohl(tmp); \
1009 Index += sizeof(int); \
1012 /* get entries count and byte count */
1013 EXTRACT_INT(num_entries, ef->data, index);
1014 EXTRACT_INT(byte_entries, ef->data, index);
1016 /* we cant have <= 0 values here - invalid */
1017 if (eet_test_close((num_entries <= 0) || (byte_entries <= 0), ef))
1020 /* we can't have more entires than minimum bytes for those! invalid! */
1021 if (eet_test_close((num_entries * 20) > byte_entries, ef))
1024 /* check we will not outrun the file limit */
1025 if (eet_test_close(((byte_entries + sizeof(int) * 3) > ef->data_size), ef))
1028 /* allocate header */
1029 ef->header = calloc(1, sizeof(Eet_File_Header));
1030 if (eet_test_close(!ef->header, ef))
1033 ef->header->magic = EET_MAGIC_FILE_HEADER;
1035 /* allocate directory block in ram */
1036 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1037 if (eet_test_close(!ef->header->directory, ef))
1040 /* 8 bit hash table (256 buckets) */
1041 ef->header->directory->size = 8;
1042 /* allocate base hash table */
1043 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1044 if (eet_test_close(!ef->header->directory->nodes, ef))
1047 /* actually read the directory block - all of it, into ram */
1048 dyn_buf = ef->data + index;
1050 /* parse directory block */
1053 for (i = 0; i < num_entries; i++)
1062 #define HEADER_SIZE (sizeof(int) * 5)
1064 /* out directory block is inconsistent - we have oveerun our */
1065 /* dynamic block buffer before we finished scanning dir entries */
1066 if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef))
1069 /* allocate all the ram needed for this stored node accounting */
1070 efn = malloc (sizeof(Eet_File_Node));
1071 if (eet_test_close(!efn, ef))
1074 /* get entrie header */
1075 EXTRACT_INT(efn->offset, p, indexn);
1076 EXTRACT_INT(efn->compression, p, indexn);
1077 EXTRACT_INT(efn->size, p, indexn);
1078 EXTRACT_INT(efn->data_size, p, indexn);
1079 EXTRACT_INT(name_size, p, indexn);
1081 efn->name_size = name_size;
1084 if (eet_test_close(efn->size <= 0, ef))
1090 /* invalid name_size */
1091 if (eet_test_close(name_size <= 0, ef))
1097 /* reading name would mean falling off end of dyn_buf - invalid */
1098 if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef))
1104 /* This code is useless if we dont want backward compatibility */
1105 for (k = name_size; k > 0 && ((unsigned char) * (p + HEADER_SIZE + k)) != 0; --k)
1108 efn->free_name = ((unsigned char) * (p + HEADER_SIZE + k)) != 0;
1112 efn->name = malloc(sizeof(char) * name_size + 1);
1113 if (eet_test_close(efn->name == NULL, ef))
1119 strncpy(efn->name, (char *)p + HEADER_SIZE, name_size);
1120 efn->name[name_size] = 0;
1122 printf("File: %s is not up to date for key \"%s\" - needs rebuilding sometime\n", ef->path, efn->name);
1125 /* The only really usefull peace of code for efn->name (no backward compatibility) */
1126 efn->name = (char*)((unsigned char*)(p + HEADER_SIZE));
1128 /* get hash bucket it should go in */
1129 hash = _eet_hash_gen(efn->name, ef->header->directory->size);
1130 efn->next = ef->header->directory->nodes[hash];
1131 ef->header->directory->nodes[hash] = efn;
1133 /* read-only mode, so currently we have no data loaded */
1134 if (ef->mode == EET_FILE_MODE_READ)
1136 /* read-write mode - read everything into ram */
1139 data = malloc(efn->size);
1141 memcpy(data, ef->data + efn->offset, efn->size);
1145 p += HEADER_SIZE + name_size;
1152 eet_internal_read(Eet_File *ef)
1154 const int *data = (const int*) ef->data;
1156 if (eet_test_close((ef->data == (void *)-1) || (ef->data == NULL), ef))
1159 if (eet_test_close(ef->data_size < sizeof(int) * 3, ef))
1162 switch (ntohl(*data))
1164 #if EET_OLD_EET_FILE_FORMAT
1165 case EET_MAGIC_FILE:
1166 return eet_internal_read1(ef);
1168 case EET_MAGIC_FILE2:
1169 return eet_internal_read2(ef);
1171 ef->delete_me_now = 1;
1180 eet_memopen_read(const void *data, size_t size)
1184 if (data == NULL || size == 0)
1187 ef = malloc (sizeof (Eet_File));
1194 ef->magic = EET_MAGIC_FILE;
1196 ef->mode = EET_FILE_MODE_READ;
1199 ef->delete_me_now = 1;
1203 ef->data_size = size;
1205 return eet_internal_read(ef);
1209 eet_open(const char *file, Eet_File_Mode mode)
1214 struct stat file_stat;
1219 /* find the current file handle in cache*/
1221 if (mode == EET_FILE_MODE_READ)
1223 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1228 ef->delete_me_now = 1;
1231 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1233 else if ((mode == EET_FILE_MODE_WRITE) ||
1234 (mode == EET_FILE_MODE_READ_WRITE))
1236 ef = eet_cache_find((char *)file, eet_readers, eet_readers_num);
1239 ef->delete_me_now = 1;
1243 ef = eet_cache_find((char *)file, eet_writers, eet_writers_num);
1246 /* try open the file based on mode */
1247 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1249 fp = fopen(file, "rb");
1250 if (!fp) goto on_error;
1251 if (fstat(fileno(fp), &file_stat))
1257 if ((mode == EET_FILE_MODE_READ) &&
1258 (file_stat.st_size < (sizeof(int) * 3)))
1266 if (fp == NULL && mode == EET_FILE_MODE_READ) return NULL;
1270 if (mode != EET_FILE_MODE_WRITE) return NULL;
1271 memset(&file_stat, 0, sizeof(file_stat));
1272 /* opening for write - delete old copy of file right away */
1274 fp = fopen(file, "wb");
1278 if (ef && (file_stat.st_mtime != ef->mtime))
1280 ef->delete_me_now = 1;
1288 /* reference it up and return it */
1289 if (fp != NULL) fclose(fp);
1294 file_len = strlen(file) + 1;
1296 /* Allocate struct for eet file and have it zero'd out */
1297 ef = malloc(sizeof(Eet_File) + file_len);
1301 /* fill some of the members */
1305 ef->path = ((char *)ef) + sizeof(Eet_File);
1306 memcpy(ef->path, file, file_len);
1307 ef->magic = EET_MAGIC_FILE;
1311 ef->mtime = file_stat.st_mtime;
1312 ef->writes_pending = 0;
1313 ef->delete_me_now = 0;
1317 ef->ed = (mode == EET_FILE_MODE_WRITE)
1318 || (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) ?
1319 eet_dictionary_add() : NULL;
1321 if (ef->fp == NULL && mode == EET_FILE_MODE_READ_WRITE) goto empty_file;
1323 /* if we can't open - bail out */
1324 if (eet_test_close(!ef->fp, ef))
1327 fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC);
1328 /* if we opened for read or read-write */
1329 if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE))
1331 ef->data_size = file_stat.st_size;
1332 ef->data = mmap(NULL, ef->data_size, PROT_READ,
1333 MAP_SHARED, fileno(ef->fp), 0);
1334 if (eet_test_close((ef->data == MAP_FAILED), ef))
1336 ef = eet_internal_read(ef);
1342 /* we need to delete the original file in read-write mode and re-open for writing */
1343 if (ef->mode == EET_FILE_MODE_READ_WRITE)
1345 ef->readfp = ef->fp;
1350 if (ef->references == 1)
1352 if (ef->mode == EET_FILE_MODE_READ)
1353 eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1355 if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1356 eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1363 eet_mode_get(Eet_File *ef)
1365 /* check to see its' an eet file pointer */
1366 if ((!ef) || (ef->magic != EET_MAGIC_FILE))
1367 return EET_FILE_MODE_INVALID;
1373 eet_identity_x509(Eet_File *ef, int *der_length)
1375 if (!ef->x509_der) return NULL;
1377 if (der_length) *der_length = ef->x509_length;
1378 return ef->x509_der;
1382 eet_identity_set(Eet_File *ef, Eet_Key *key)
1384 Eet_Key *tmp = ef->key;
1386 if (!ef) return EET_ERROR_BAD_OBJECT;
1389 eet_identity_ref(ef->key);
1390 eet_identity_unref(tmp);
1392 /* flags that writes are pending */
1393 ef->writes_pending = 1;
1395 return EET_ERROR_NONE;
1399 eet_close(Eet_File *ef)
1403 /* check to see its' an eet file pointer */
1404 if (eet_check_pointer(ef))
1405 return EET_ERROR_BAD_OBJECT;
1408 /* if its still referenced - dont go any further */
1409 if (ef->references > 0) return EET_ERROR_NONE;
1410 /* flush any writes */
1411 err = eet_flush2(ef);
1413 eet_identity_unref(ef->key);
1416 /* if not urgent to delete it - dont free it - leave it in cache */
1417 if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ))
1418 return EET_ERROR_NONE;
1420 /* remove from cache */
1421 if (ef->mode == EET_FILE_MODE_READ)
1422 eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc);
1423 else if ((ef->mode == EET_FILE_MODE_WRITE) || (ef->mode == EET_FILE_MODE_READ_WRITE))
1424 eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc);
1429 if (ef->header->directory)
1431 if (ef->header->directory->nodes)
1435 num = (1 << ef->header->directory->size);
1436 for (i = 0; i < num; i++)
1440 while ((efn = ef->header->directory->nodes[i]))
1445 ef->header->directory->nodes[i] = efn->next;
1453 free(ef->header->directory->nodes);
1455 free(ef->header->directory);
1460 eet_dictionary_free(ef->ed);
1462 if (ef->data) munmap((void*)ef->data, ef->data_size);
1463 if (ef->fp) fclose(ef->fp);
1464 if (ef->readfp) fclose(ef->readfp);
1466 /* zero out ram for struct - caution tactic against stale memory use */
1467 memset(ef, 0, sizeof(Eet_File));
1475 eet_read(Eet_File *ef, const char *name, int *size_ret)
1484 /* check to see its' an eet file pointer */
1485 if (eet_check_pointer(ef))
1489 if ((ef->mode != EET_FILE_MODE_READ) &&
1490 (ef->mode != EET_FILE_MODE_READ_WRITE))
1493 /* no header, return NULL */
1494 if (eet_check_header(ef))
1497 /* hunt hash bucket */
1498 efn = find_node_by_name(ef, name);
1502 /* get size (uncompressed, if compressed at all) */
1503 size = efn->data_size;
1506 data = malloc(size);
1510 /* uncompressed data */
1511 if (efn->compression == 0)
1513 /* if we alreayd have the data in ram... copy that */
1515 memcpy(data, efn->data, efn->size);
1517 if (!read_data_from_disk(ef, efn, data, size))
1523 /* compressed data */
1528 int compr_size = efn->size;
1531 /* if we already have the data in ram... copy that */
1533 tmp_data = efn->data;
1536 tmp_data = malloc(compr_size);
1545 if (!read_data_from_disk(ef, efn, tmp_data, compr_size))
1555 if (uncompress((Bytef *)data, &dlen,
1556 tmp_data, (uLongf)compr_size))
1566 /* fill in return values */
1574 eet_read_direct(Eet_File *ef, const char *name, int *size_ret)
1576 const void *data = NULL;
1583 /* check to see its' an eet file pointer */
1584 if (eet_check_pointer(ef))
1588 if ((ef->mode != EET_FILE_MODE_READ) &&
1589 (ef->mode != EET_FILE_MODE_READ_WRITE))
1592 /* no header, return NULL */
1593 if (eet_check_header(ef))
1596 /* hunt hash bucket */
1597 efn = find_node_by_name(ef, name);
1601 if (efn->offset < 0 && efn->data == NULL)
1604 /* get size (uncompressed, if compressed at all) */
1605 size = efn->data_size;
1607 /* uncompressed data */
1608 if (efn->compression == 0)
1609 data = efn->data ? efn->data : ef->data + efn->offset;
1610 /* compressed data */
1614 /* fill in return values */
1622 eet_write(Eet_File *ef, const char *name, const void *data, int size, int compress)
1626 int exists_already = 0;
1630 /* check to see its' an eet file pointer */
1631 if (eet_check_pointer(ef))
1633 if ((!name) || (!data) || (size <= 0))
1635 if ((ef->mode != EET_FILE_MODE_WRITE) &&
1636 (ef->mode != EET_FILE_MODE_READ_WRITE))
1641 /* allocate header */
1642 ef->header = calloc(1, sizeof(Eet_File_Header));
1646 ef->header->magic = EET_MAGIC_FILE_HEADER;
1647 /* allocate directory block in ram */
1648 ef->header->directory = calloc(1, sizeof(Eet_File_Directory));
1649 if (!ef->header->directory)
1652 /* 8 bit hash table (256 buckets) */
1653 ef->header->directory->size = 8;
1654 /* allocate base hash table */
1655 ef->header->directory->nodes = calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size));
1656 if (!ef->header->directory->nodes)
1660 /* figure hash bucket */
1661 hash = _eet_hash_gen(name, ef->header->directory->size);
1663 data_size = compress ? 12 + ((size * 101) / 100) : size;
1665 data2 = malloc(data_size);
1669 /* if we want to compress */
1674 /* compress the data with max compression */
1675 buflen = (uLongf)data_size;
1676 if (compress2((Bytef *)data2, &buflen, (Bytef *)data,
1677 (uLong)size, Z_BEST_COMPRESSION) != Z_OK)
1682 /* record compressed chunk size */
1683 data_size = (int)buflen;
1684 if (data_size < 0 || data_size >= size)
1693 data3 = realloc(data2, data_size);
1699 memcpy(data2, data, size);
1701 /* Does this node already exist? */
1702 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
1705 if ((efn->name) && (eet_string_match(efn->name, name)))
1708 efn->compression = !!compress;
1709 efn->size = data_size;
1710 efn->data_size = size;
1717 if (!exists_already)
1719 efn = malloc(sizeof(Eet_File_Node));
1725 efn->name = strdup(name);
1726 efn->name_size = strlen(efn->name) + 1;
1729 efn->next = ef->header->directory->nodes[hash];
1730 ef->header->directory->nodes[hash] = efn;
1732 efn->compression = !!compress;
1733 efn->size = data_size;
1734 efn->data_size = size;
1738 /* flags that writes are pending */
1739 ef->writes_pending = 1;
1744 eet_delete(Eet_File *ef, const char *name)
1747 Eet_File_Node *pefn;
1749 int exists_already = 0;
1751 /* check to see its' an eet file pointer */
1752 if (eet_check_pointer(ef))
1757 /* deleting keys is only possible in RW or WRITE mode */
1758 if (ef->mode == EET_FILE_MODE_READ)
1761 if (eet_check_header(ef))
1764 /* figure hash bucket */
1765 hash = _eet_hash_gen(name, ef->header->directory->size);
1767 /* Does this node already exist? */
1768 for (pefn = NULL, efn = ef->header->directory->nodes[hash];
1770 pefn = efn, efn = efn->next)
1773 if (eet_string_match(efn->name, name))
1778 if (efn == ef->header->directory->nodes[hash])
1779 ef->header->directory->nodes[hash] = efn->next;
1781 pefn->next = efn->next;
1783 if (efn->free_name) free(efn->name);
1789 /* flags that writes are pending */
1791 ef->writes_pending = 1;
1793 /* update access time */
1794 return exists_already;
1797 EAPI Eet_Dictionary *
1798 eet_dictionary_get(Eet_File *ef)
1800 if (eet_check_pointer(ef)) return NULL;
1807 eet_list(Eet_File *ef, const char *glob, int *count_ret)
1810 char **list_ret = NULL;
1812 int list_count_alloc = 0;
1815 /* check to see its' an eet file pointer */
1816 if (eet_check_pointer(ef) || eet_check_header(ef) ||
1818 ((ef->mode != EET_FILE_MODE_READ) &&
1819 (ef->mode != EET_FILE_MODE_READ_WRITE)))
1827 /* loop through all entries */
1828 num = (1 << ef->header->directory->size);
1829 for (i = 0; i < num; i++)
1831 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
1833 /* if the entry matches the input glob
1834 * check for * explicitly, because on some systems, * isn't well
1837 if ((!strcmp (glob, "*")) || !fnmatch(glob, efn->name, 0))
1839 /* add it to our list */
1842 /* only realloc in 32 entry chunks */
1843 if (list_count > list_count_alloc)
1845 char **new_list = NULL;
1847 list_count_alloc += 64;
1848 new_list = realloc(list_ret, list_count_alloc * (sizeof(char *)));
1858 list_ret = new_list;
1861 /* put pointer of name string in */
1862 list_ret[list_count - 1] = efn->name;
1867 /* return count and list */
1869 *count_ret = list_count;
1875 eet_num_entries(Eet_File *ef)
1877 int i, num, ret = 0;
1880 /* check to see its' an eet file pointer */
1881 if (eet_check_pointer(ef) || eet_check_header(ef) ||
1882 ((ef->mode != EET_FILE_MODE_READ) &&
1883 (ef->mode != EET_FILE_MODE_READ_WRITE)))
1886 /* loop through all entries */
1887 num = (1 << ef->header->directory->size);
1888 for (i = 0; i < num; i++)
1890 for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next)
1897 static Eet_File_Node *
1898 find_node_by_name(Eet_File *ef, const char *name)
1903 /* get hash bucket this should be in */
1904 hash = _eet_hash_gen(name, ef->header->directory->size);
1906 for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next)
1908 if (eet_string_match(efn->name, name))
1916 read_data_from_disk(Eet_File *ef, Eet_File_Node *efn, void *buf, int len)
1918 if (efn->offset < 0) return 0;
1922 if ((efn->offset + len) > ef->data_size) return 0;
1923 memcpy(buf, ef->data + efn->offset, len);
1927 /* seek to data location */
1928 if (fseek(ef->fp, efn->offset, SEEK_SET) < 0)
1932 len = fread(buf, len, 1, ef->fp);