diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/eet/src/lib/eet_lib.c | 2533 |
1 files changed, 0 insertions, 2533 deletions
diff --git a/libraries/eet/src/lib/eet_lib.c b/libraries/eet/src/lib/eet_lib.c deleted file mode 100644 index 04feebe..0000000 --- a/libraries/eet/src/lib/eet_lib.c +++ /dev/null | |||
@@ -1,2533 +0,0 @@ | |||
1 | #ifdef HAVE_CONFIG_H | ||
2 | # include <config.h> | ||
3 | #endif /* ifdef HAVE_CONFIG_H */ | ||
4 | |||
5 | #ifdef HAVE_ALLOCA_H | ||
6 | # include <alloca.h> | ||
7 | #elif defined __GNUC__ | ||
8 | # define alloca __builtin_alloca | ||
9 | #elif defined _AIX | ||
10 | # define alloca __alloca | ||
11 | #elif defined _MSC_VER | ||
12 | # include <malloc.h> | ||
13 | # define alloca _alloca | ||
14 | #else /* ifdef HAVE_ALLOCA_H */ | ||
15 | # include <stddef.h> | ||
16 | # ifdef __cplusplus | ||
17 | extern "C" | ||
18 | # endif /* ifdef __cplusplus */ | ||
19 | void *alloca(size_t); | ||
20 | #endif /* ifdef HAVE_ALLOCA_H */ | ||
21 | |||
22 | #ifdef _WIN32 | ||
23 | # include <winsock2.h> | ||
24 | #endif /* ifdef _WIN32 */ | ||
25 | |||
26 | #include <stdio.h> | ||
27 | #include <errno.h> | ||
28 | #include <sys/types.h> | ||
29 | #include <sys/stat.h> | ||
30 | #include <time.h> | ||
31 | #include <string.h> | ||
32 | #include <fnmatch.h> | ||
33 | #include <fcntl.h> | ||
34 | #include <zlib.h> | ||
35 | |||
36 | #ifdef HAVE_UNISTD_H | ||
37 | # include <unistd.h> | ||
38 | #endif /* ifdef HAVE_UNISTD_H */ | ||
39 | |||
40 | #ifdef HAVE_NETINET_IN_H | ||
41 | # include <netinet/in.h> | ||
42 | #endif /* ifdef HAVE_NETINET_IN_H */ | ||
43 | |||
44 | #ifdef HAVE_EVIL | ||
45 | # include <Evil.h> | ||
46 | #endif /* ifdef HAVE_EVIL */ | ||
47 | |||
48 | #include <Eina.h> | ||
49 | |||
50 | #ifdef HAVE_GNUTLS | ||
51 | # include <gnutls/gnutls.h> | ||
52 | # include <gcrypt.h> | ||
53 | #endif /* ifdef HAVE_GNUTLS */ | ||
54 | |||
55 | #ifdef HAVE_OPENSSL | ||
56 | # include <openssl/err.h> | ||
57 | # include <openssl/evp.h> | ||
58 | #endif /* ifdef HAVE_OPENSSL */ | ||
59 | |||
60 | #ifdef EINA_HAVE_THREADS | ||
61 | # ifdef HAVE_GNUTLS | ||
62 | GCRY_THREAD_OPTION_PTHREAD_IMPL; | ||
63 | # endif /* ifdef HAVE_GNUTLS */ | ||
64 | #endif /* ifdef EINA_HAVE_THREADS */ | ||
65 | |||
66 | #include "Eet.h" | ||
67 | #include "Eet_private.h" | ||
68 | |||
69 | #ifndef O_BINARY | ||
70 | # define O_BINARY 0 | ||
71 | #endif | ||
72 | |||
73 | static Eet_Version _version = { VMAJ, VMIN, VMIC, VREV }; | ||
74 | EAPI Eet_Version *eet_version = &_version; | ||
75 | |||
76 | #ifdef HAVE_REALPATH | ||
77 | # undef HAVE_REALPATH | ||
78 | #endif /* ifdef HAVE_REALPATH */ | ||
79 | |||
80 | #define EET_MAGIC_FILE 0x1ee7ff00 | ||
81 | #define EET_MAGIC_FILE_HEADER 0x1ee7ff01 | ||
82 | |||
83 | #define EET_MAGIC_FILE2 0x1ee70f42 | ||
84 | |||
85 | #define EET_FILE2_HEADER_COUNT 3 | ||
86 | #define EET_FILE2_DIRECTORY_ENTRY_COUNT 6 | ||
87 | #define EET_FILE2_DICTIONARY_ENTRY_COUNT 5 | ||
88 | |||
89 | #define EET_FILE2_HEADER_SIZE (sizeof(int) * \ | ||
90 | EET_FILE2_HEADER_COUNT) | ||
91 | #define EET_FILE2_DIRECTORY_ENTRY_SIZE (sizeof(int) * \ | ||
92 | EET_FILE2_DIRECTORY_ENTRY_COUNT) | ||
93 | #define EET_FILE2_DICTIONARY_ENTRY_SIZE (sizeof(int) * \ | ||
94 | EET_FILE2_DICTIONARY_ENTRY_COUNT) | ||
95 | |||
96 | /* prototypes of internal calls */ | ||
97 | static Eet_File * | ||
98 | eet_cache_find(const char *path, | ||
99 | Eet_File **cache, | ||
100 | int cache_num); | ||
101 | static void | ||
102 | eet_cache_add(Eet_File *ef, | ||
103 | Eet_File ***cache, | ||
104 | int *cache_num, | ||
105 | int *cache_alloc); | ||
106 | static void | ||
107 | eet_cache_del(Eet_File *ef, | ||
108 | Eet_File ***cache, | ||
109 | int *cache_num, | ||
110 | int *cache_alloc); | ||
111 | static int | ||
112 | eet_string_match(const char *s1, | ||
113 | const char *s2); | ||
114 | #if 0 /* Unused */ | ||
115 | static Eet_Error | ||
116 | eet_flush(Eet_File *ef); | ||
117 | #endif /* if 0 */ | ||
118 | static Eet_Error | ||
119 | eet_flush2(Eet_File *ef); | ||
120 | static Eet_File_Node * | ||
121 | find_node_by_name(Eet_File *ef, | ||
122 | const char *name); | ||
123 | static int | ||
124 | read_data_from_disk(Eet_File *ef, | ||
125 | Eet_File_Node *efn, | ||
126 | void *buf, | ||
127 | int len); | ||
128 | |||
129 | static Eet_Error | ||
130 | eet_internal_close(Eet_File *ef, | ||
131 | Eina_Bool locked); | ||
132 | |||
133 | static Eina_Lock eet_cache_lock; | ||
134 | |||
135 | #define LOCK_CACHE eina_lock_take(&eet_cache_lock) | ||
136 | #define UNLOCK_CACHE eina_lock_release(&eet_cache_lock) | ||
137 | |||
138 | #define INIT_FILE(File) eina_lock_new(&File->file_lock) | ||
139 | #define LOCK_FILE(File) eina_lock_take(&File->file_lock) | ||
140 | #define UNLOCK_FILE(File) eina_lock_release(&File->file_lock) | ||
141 | #define DESTROY_FILE(File) eina_lock_free(&File->file_lock) | ||
142 | |||
143 | /* cache. i don't expect this to ever be large, so arrays will do */ | ||
144 | static int eet_writers_num = 0; | ||
145 | static int eet_writers_alloc = 0; | ||
146 | static Eet_File **eet_writers = NULL; | ||
147 | static int eet_readers_num = 0; | ||
148 | static int eet_readers_alloc = 0; | ||
149 | static Eet_File **eet_readers = NULL; | ||
150 | static int eet_init_count = 0; | ||
151 | |||
152 | /* log domain variable */ | ||
153 | int _eet_log_dom_global = -1; | ||
154 | |||
155 | /* Check to see its' an eet file pointer */ | ||
156 | static inline int | ||
157 | eet_check_pointer(const Eet_File *ef) | ||
158 | { | ||
159 | if ((!ef) || (ef->magic != EET_MAGIC_FILE)) | ||
160 | return 1; | ||
161 | |||
162 | return 0; | ||
163 | } | ||
164 | |||
165 | static inline int | ||
166 | eet_check_header(const Eet_File *ef) | ||
167 | { | ||
168 | if (!ef->header) | ||
169 | return 1; | ||
170 | |||
171 | if (!ef->header->directory) | ||
172 | return 1; | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static inline int | ||
178 | eet_test_close(int test, | ||
179 | Eet_File *ef) | ||
180 | { | ||
181 | if (test) | ||
182 | { | ||
183 | ef->delete_me_now = 1; | ||
184 | eet_internal_close(ef, EINA_TRUE); | ||
185 | } | ||
186 | |||
187 | return test; | ||
188 | } | ||
189 | |||
190 | /* find an eet file in the currently in use cache */ | ||
191 | static Eet_File * | ||
192 | eet_cache_find(const char *path, | ||
193 | Eet_File **cache, | ||
194 | int cache_num) | ||
195 | { | ||
196 | int i; | ||
197 | |||
198 | /* walk list */ | ||
199 | for (i = 0; i < cache_num; i++) | ||
200 | { | ||
201 | /* if matches real path - return it */ | ||
202 | if (eet_string_match(cache[i]->path, path)) | ||
203 | if (!cache[i]->delete_me_now) | ||
204 | return cache[i]; | ||
205 | } | ||
206 | |||
207 | /* not found */ | ||
208 | return NULL; | ||
209 | } | ||
210 | |||
211 | /* add to end of cache */ | ||
212 | /* this should only be called when the cache lock is already held */ | ||
213 | static void | ||
214 | eet_cache_add(Eet_File *ef, | ||
215 | Eet_File ***cache, | ||
216 | int *cache_num, | ||
217 | int *cache_alloc) | ||
218 | { | ||
219 | Eet_File **new_cache; | ||
220 | int new_cache_num; | ||
221 | int new_cache_alloc; | ||
222 | |||
223 | new_cache_num = *cache_num; | ||
224 | if (new_cache_num >= 64) /* avoid fd overruns - limit to 128 (most recent) in the cache */ | ||
225 | { | ||
226 | Eet_File *del_ef = NULL; | ||
227 | int i; | ||
228 | |||
229 | new_cache = *cache; | ||
230 | for (i = 0; i < new_cache_num; i++) | ||
231 | { | ||
232 | if (new_cache[i]->references == 0) | ||
233 | { | ||
234 | del_ef = new_cache[i]; | ||
235 | break; | ||
236 | } | ||
237 | } | ||
238 | |||
239 | if (del_ef) | ||
240 | { | ||
241 | del_ef->delete_me_now = 1; | ||
242 | eet_internal_close(del_ef, EINA_TRUE); | ||
243 | } | ||
244 | } | ||
245 | |||
246 | new_cache = *cache; | ||
247 | new_cache_num = *cache_num; | ||
248 | new_cache_alloc = *cache_alloc; | ||
249 | new_cache_num++; | ||
250 | if (new_cache_num > new_cache_alloc) | ||
251 | { | ||
252 | new_cache_alloc += 16; | ||
253 | new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *)); | ||
254 | if (!new_cache) | ||
255 | { | ||
256 | CRIT("BAD ERROR! Eet realloc of cache list failed. Abort"); | ||
257 | abort(); | ||
258 | } | ||
259 | } | ||
260 | |||
261 | new_cache[new_cache_num - 1] = ef; | ||
262 | *cache = new_cache; | ||
263 | *cache_num = new_cache_num; | ||
264 | *cache_alloc = new_cache_alloc; | ||
265 | } | ||
266 | |||
267 | /* delete from cache */ | ||
268 | /* this should only be called when the cache lock is already held */ | ||
269 | static void | ||
270 | eet_cache_del(Eet_File *ef, | ||
271 | Eet_File ***cache, | ||
272 | int *cache_num, | ||
273 | int *cache_alloc) | ||
274 | { | ||
275 | Eet_File **new_cache; | ||
276 | int new_cache_num, new_cache_alloc; | ||
277 | int i, j; | ||
278 | |||
279 | new_cache = *cache; | ||
280 | new_cache_num = *cache_num; | ||
281 | new_cache_alloc = *cache_alloc; | ||
282 | if (new_cache_num <= 0) | ||
283 | return; | ||
284 | |||
285 | for (i = 0; i < new_cache_num; i++) | ||
286 | { | ||
287 | if (new_cache[i] == ef) | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | if (i >= new_cache_num) | ||
292 | return; | ||
293 | |||
294 | new_cache_num--; | ||
295 | for (j = i; j < new_cache_num; j++) | ||
296 | new_cache[j] = new_cache[j + 1]; | ||
297 | |||
298 | if (new_cache_num <= (new_cache_alloc - 16)) | ||
299 | { | ||
300 | new_cache_alloc -= 16; | ||
301 | if (new_cache_num > 0) | ||
302 | { | ||
303 | new_cache = realloc(new_cache, new_cache_alloc * sizeof(Eet_File *)); | ||
304 | if (!new_cache) | ||
305 | { | ||
306 | CRIT("BAD ERROR! Eet realloc of cache list failed. Abort"); | ||
307 | abort(); | ||
308 | } | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | free(new_cache); | ||
313 | new_cache = NULL; | ||
314 | } | ||
315 | } | ||
316 | |||
317 | *cache = new_cache; | ||
318 | *cache_num = new_cache_num; | ||
319 | *cache_alloc = new_cache_alloc; | ||
320 | } | ||
321 | |||
322 | /* internal string match. null friendly, catches same ptr */ | ||
323 | static int | ||
324 | eet_string_match(const char *s1, | ||
325 | const char *s2) | ||
326 | { | ||
327 | /* both null- no match */ | ||
328 | if ((!s1) || (!s2)) | ||
329 | return 0; | ||
330 | |||
331 | if (s1 == s2) | ||
332 | return 1; | ||
333 | |||
334 | return !strcmp(s1, s2); | ||
335 | } | ||
336 | |||
337 | /* flush out writes to a v2 eet file */ | ||
338 | static Eet_Error | ||
339 | eet_flush2(Eet_File *ef) | ||
340 | { | ||
341 | Eet_File_Node *efn; | ||
342 | FILE *fp; | ||
343 | Eet_Error error = EET_ERROR_NONE; | ||
344 | int head[EET_FILE2_HEADER_COUNT]; | ||
345 | int num_directory_entries = 0; | ||
346 | int num_dictionary_entries = 0; | ||
347 | int bytes_directory_entries = 0; | ||
348 | int bytes_dictionary_entries = 0; | ||
349 | int bytes_strings = 0; | ||
350 | int data_offset = 0; | ||
351 | int strings_offset = 0; | ||
352 | int num; | ||
353 | int i; | ||
354 | int j; | ||
355 | |||
356 | if (eet_check_pointer(ef)) | ||
357 | return EET_ERROR_BAD_OBJECT; | ||
358 | |||
359 | if (eet_check_header(ef)) | ||
360 | return EET_ERROR_EMPTY; | ||
361 | |||
362 | if (!ef->writes_pending) | ||
363 | return EET_ERROR_NONE; | ||
364 | |||
365 | if ((ef->mode == EET_FILE_MODE_READ_WRITE) | ||
366 | || (ef->mode == EET_FILE_MODE_WRITE)) | ||
367 | { | ||
368 | int fd; | ||
369 | |||
370 | /* opening for write - delete old copy of file right away */ | ||
371 | unlink(ef->path); | ||
372 | fd = open(ef->path, O_CREAT | O_TRUNC | O_RDWR | O_BINARY, S_IRUSR | S_IWUSR); | ||
373 | fp = fdopen(fd, "wb"); | ||
374 | if (!fp) | ||
375 | return EET_ERROR_NOT_WRITABLE; | ||
376 | |||
377 | fcntl(fd, F_SETFD, FD_CLOEXEC); | ||
378 | } | ||
379 | else | ||
380 | return EET_ERROR_NOT_WRITABLE; | ||
381 | |||
382 | /* calculate string base offset and data base offset */ | ||
383 | num = (1 << ef->header->directory->size); | ||
384 | for (i = 0; i < num; ++i) | ||
385 | { | ||
386 | for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) | ||
387 | { | ||
388 | num_directory_entries++; | ||
389 | bytes_strings += strlen(efn->name) + 1; | ||
390 | } | ||
391 | } | ||
392 | if (ef->ed) | ||
393 | { | ||
394 | num_dictionary_entries = ef->ed->count; | ||
395 | |||
396 | for (i = 0; i < num_dictionary_entries; ++i) | ||
397 | bytes_strings += ef->ed->all[i].len; | ||
398 | } | ||
399 | |||
400 | /* calculate section bytes size */ | ||
401 | bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * | ||
402 | num_directory_entries + EET_FILE2_HEADER_SIZE; | ||
403 | bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * | ||
404 | num_dictionary_entries; | ||
405 | |||
406 | /* calculate per entry offset */ | ||
407 | strings_offset = bytes_directory_entries + bytes_dictionary_entries; | ||
408 | data_offset = bytes_directory_entries + bytes_dictionary_entries + | ||
409 | bytes_strings; | ||
410 | |||
411 | for (i = 0; i < num; ++i) | ||
412 | { | ||
413 | for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) | ||
414 | { | ||
415 | efn->offset = data_offset; | ||
416 | data_offset += efn->size; | ||
417 | |||
418 | efn->name_offset = strings_offset; | ||
419 | strings_offset += efn->name_size; | ||
420 | } | ||
421 | } | ||
422 | |||
423 | /* calculate dictionary strings offset */ | ||
424 | if (ef->ed) | ||
425 | ef->ed->offset = strings_offset; | ||
426 | |||
427 | /* go thru and write the header */ | ||
428 | head[0] = (int)htonl((unsigned int)EET_MAGIC_FILE2); | ||
429 | head[1] = (int)htonl((unsigned int)num_directory_entries); | ||
430 | head[2] = (int)htonl((unsigned int)num_dictionary_entries); | ||
431 | |||
432 | fseek(fp, 0, SEEK_SET); | ||
433 | if (fwrite(head, sizeof (head), 1, fp) != 1) | ||
434 | goto write_error; | ||
435 | |||
436 | /* write directories entry */ | ||
437 | for (i = 0; i < num; i++) | ||
438 | { | ||
439 | for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) | ||
440 | { | ||
441 | unsigned int flag; | ||
442 | int ibuf[EET_FILE2_DIRECTORY_ENTRY_COUNT]; | ||
443 | |||
444 | flag = (efn->alias << 2) | (efn->ciphered << 1) | efn->compression; | ||
445 | |||
446 | ibuf[0] = (int)htonl((unsigned int)efn->offset); | ||
447 | ibuf[1] = (int)htonl((unsigned int)efn->size); | ||
448 | ibuf[2] = (int)htonl((unsigned int)efn->data_size); | ||
449 | ibuf[3] = (int)htonl((unsigned int)efn->name_offset); | ||
450 | ibuf[4] = (int)htonl((unsigned int)efn->name_size); | ||
451 | ibuf[5] = (int)htonl((unsigned int)flag); | ||
452 | |||
453 | if (fwrite(ibuf, sizeof(ibuf), 1, fp) != 1) | ||
454 | goto write_error; | ||
455 | } | ||
456 | } | ||
457 | |||
458 | /* write dictionary */ | ||
459 | if (ef->ed) | ||
460 | { | ||
461 | int offset = strings_offset; | ||
462 | |||
463 | for (j = 0; j < ef->ed->count; ++j) | ||
464 | { | ||
465 | int sbuf[EET_FILE2_DICTIONARY_ENTRY_COUNT]; | ||
466 | |||
467 | sbuf[0] = (int)htonl((unsigned int)ef->ed->all[j].hash); | ||
468 | sbuf[1] = (int)htonl((unsigned int)offset); | ||
469 | sbuf[2] = (int)htonl((unsigned int)ef->ed->all[j].len); | ||
470 | sbuf[3] = (int)htonl((unsigned int)ef->ed->all[j].prev); | ||
471 | sbuf[4] = (int)htonl((unsigned int)ef->ed->all[j].next); | ||
472 | |||
473 | offset += ef->ed->all[j].len; | ||
474 | |||
475 | if (fwrite(sbuf, sizeof (sbuf), 1, fp) != 1) | ||
476 | goto write_error; | ||
477 | } | ||
478 | } | ||
479 | |||
480 | /* write directories name */ | ||
481 | for (i = 0; i < num; i++) | ||
482 | { | ||
483 | for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) | ||
484 | { | ||
485 | if (fwrite(efn->name, efn->name_size, 1, fp) != 1) | ||
486 | goto write_error; | ||
487 | } | ||
488 | } | ||
489 | |||
490 | /* write strings */ | ||
491 | if (ef->ed) | ||
492 | for (j = 0; j < ef->ed->count; ++j) | ||
493 | { | ||
494 | if (fwrite(ef->ed->all[j].str, ef->ed->all[j].len, 1, fp) != 1) | ||
495 | goto write_error; | ||
496 | } | ||
497 | |||
498 | /* write data */ | ||
499 | for (i = 0; i < num; i++) | ||
500 | { | ||
501 | for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) | ||
502 | { | ||
503 | if (fwrite(efn->data, efn->size, 1, fp) != 1) | ||
504 | goto write_error; | ||
505 | } | ||
506 | } | ||
507 | |||
508 | /* flush all write to the file. */ | ||
509 | fflush(fp); | ||
510 | |||
511 | /* append signature if required */ | ||
512 | if (ef->key) | ||
513 | { | ||
514 | error = eet_identity_sign(fp, ef->key); | ||
515 | if (error != EET_ERROR_NONE) | ||
516 | goto sign_error; | ||
517 | } | ||
518 | |||
519 | /* no more writes pending */ | ||
520 | ef->writes_pending = 0; | ||
521 | |||
522 | fclose(fp); | ||
523 | |||
524 | return EET_ERROR_NONE; | ||
525 | |||
526 | write_error: | ||
527 | if (ferror(fp)) | ||
528 | { | ||
529 | switch (errno) | ||
530 | { | ||
531 | case EFBIG: error = EET_ERROR_WRITE_ERROR_FILE_TOO_BIG; break; | ||
532 | |||
533 | case EIO: error = EET_ERROR_WRITE_ERROR_IO_ERROR; break; | ||
534 | |||
535 | case ENOSPC: error = EET_ERROR_WRITE_ERROR_OUT_OF_SPACE; break; | ||
536 | |||
537 | case EPIPE: error = EET_ERROR_WRITE_ERROR_FILE_CLOSED; break; | ||
538 | |||
539 | default: error = EET_ERROR_WRITE_ERROR; break; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | sign_error: | ||
544 | fclose(fp); | ||
545 | return error; | ||
546 | } | ||
547 | |||
548 | EAPI int | ||
549 | eet_init(void) | ||
550 | { | ||
551 | if (++eet_init_count != 1) | ||
552 | return eet_init_count; | ||
553 | |||
554 | if (!eina_init()) | ||
555 | return --eet_init_count; | ||
556 | |||
557 | _eet_log_dom_global = eina_log_domain_register("eet", EET_DEFAULT_LOG_COLOR); | ||
558 | if (_eet_log_dom_global < 0) | ||
559 | { | ||
560 | EINA_LOG_ERR("Eet Can not create a general log domain."); | ||
561 | goto shutdown_eina; | ||
562 | } | ||
563 | |||
564 | eina_lock_new(&eet_cache_lock); | ||
565 | |||
566 | if (!eet_mempool_init()) | ||
567 | { | ||
568 | EINA_LOG_ERR("Eet: Eet_Node mempool creation failed"); | ||
569 | goto unregister_log_domain; | ||
570 | } | ||
571 | |||
572 | if (!eet_node_init()) | ||
573 | { | ||
574 | EINA_LOG_ERR("Eet: Eet_Node mempool creation failed"); | ||
575 | goto shutdown_mempool; | ||
576 | } | ||
577 | |||
578 | #ifdef HAVE_GNUTLS | ||
579 | /* Before the library can be used, it must initialize itself if needed. */ | ||
580 | if (gcry_control(GCRYCTL_ANY_INITIALIZATION_P) == 0) | ||
581 | { | ||
582 | gcry_check_version(NULL); | ||
583 | /* Disable warning messages about problems with the secure memory subsystem. | ||
584 | This command should be run right after gcry_check_version. */ | ||
585 | if (gcry_control(GCRYCTL_DISABLE_SECMEM_WARN)) | ||
586 | goto shutdown_eet; /* This command is used to allocate a pool of secure memory and thus | ||
587 | enabling the use of secure memory. It also drops all extra privileges the | ||
588 | process has (i.e. if it is run as setuid (root)). If the argument nbytes | ||
589 | is 0, secure memory will be disabled. The minimum amount of secure memory | ||
590 | allocated is currently 16384 bytes; you may thus use a value of 1 to | ||
591 | request that default size. */ | ||
592 | |||
593 | if (gcry_control(GCRYCTL_INIT_SECMEM, 16384, 0)) | ||
594 | WRN( | ||
595 | "BIG FAT WARNING: I AM UNABLE TO REQUEST SECMEM, Cryptographic operation are at risk !"); | ||
596 | } | ||
597 | |||
598 | # ifdef EINA_HAVE_THREADS | ||
599 | if (gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread)) | ||
600 | WRN( | ||
601 | "YOU ARE USING PTHREADS, BUT I CANNOT INITIALIZE THREADSAFE GCRYPT OPERATIONS!"); | ||
602 | |||
603 | # endif /* ifdef EINA_HAVE_THREADS */ | ||
604 | if (gnutls_global_init()) | ||
605 | goto shutdown_eet; | ||
606 | |||
607 | #endif /* ifdef HAVE_GNUTLS */ | ||
608 | #ifdef HAVE_OPENSSL | ||
609 | ERR_load_crypto_strings(); | ||
610 | OpenSSL_add_all_algorithms(); | ||
611 | #endif /* ifdef HAVE_OPENSSL */ | ||
612 | |||
613 | return eet_init_count; | ||
614 | |||
615 | #ifdef HAVE_GNUTLS | ||
616 | shutdown_eet: | ||
617 | #endif | ||
618 | eet_node_shutdown(); | ||
619 | shutdown_mempool: | ||
620 | eet_mempool_shutdown(); | ||
621 | unregister_log_domain: | ||
622 | eina_log_domain_unregister(_eet_log_dom_global); | ||
623 | _eet_log_dom_global = -1; | ||
624 | shutdown_eina: | ||
625 | eina_shutdown(); | ||
626 | return --eet_init_count; | ||
627 | } | ||
628 | |||
629 | EAPI int | ||
630 | eet_shutdown(void) | ||
631 | { | ||
632 | if (--eet_init_count != 0) | ||
633 | return eet_init_count; | ||
634 | |||
635 | eet_clearcache(); | ||
636 | eet_node_shutdown(); | ||
637 | eet_mempool_shutdown(); | ||
638 | |||
639 | eina_lock_free(&eet_cache_lock); | ||
640 | |||
641 | #ifdef HAVE_GNUTLS | ||
642 | gnutls_global_deinit(); | ||
643 | #endif /* ifdef HAVE_GNUTLS */ | ||
644 | #ifdef HAVE_OPENSSL | ||
645 | EVP_cleanup(); | ||
646 | ERR_free_strings(); | ||
647 | #endif /* ifdef HAVE_OPENSSL */ | ||
648 | eina_log_domain_unregister(_eet_log_dom_global); | ||
649 | _eet_log_dom_global = -1; | ||
650 | eina_shutdown(); | ||
651 | |||
652 | return eet_init_count; | ||
653 | } | ||
654 | |||
655 | EAPI Eet_Error | ||
656 | eet_sync(Eet_File *ef) | ||
657 | { | ||
658 | Eet_Error ret; | ||
659 | |||
660 | if (eet_check_pointer(ef)) | ||
661 | return EET_ERROR_BAD_OBJECT; | ||
662 | |||
663 | if ((ef->mode != EET_FILE_MODE_WRITE) && | ||
664 | (ef->mode != EET_FILE_MODE_READ_WRITE)) | ||
665 | return EET_ERROR_NOT_WRITABLE; | ||
666 | |||
667 | if (!ef->writes_pending) | ||
668 | return EET_ERROR_NONE; | ||
669 | |||
670 | LOCK_FILE(ef); | ||
671 | |||
672 | ret = eet_flush2(ef); | ||
673 | |||
674 | UNLOCK_FILE(ef); | ||
675 | return ret; | ||
676 | } | ||
677 | |||
678 | EAPI void | ||
679 | eet_clearcache(void) | ||
680 | { | ||
681 | int num = 0; | ||
682 | int i; | ||
683 | |||
684 | /* | ||
685 | * We need to compute the list of eet file to close separately from the cache, | ||
686 | * due to eet_close removing them from the cache after each call. | ||
687 | */ | ||
688 | LOCK_CACHE; | ||
689 | for (i = 0; i < eet_writers_num; i++) | ||
690 | { | ||
691 | if (eet_writers[i]->references <= 0) | ||
692 | num++; | ||
693 | } | ||
694 | |||
695 | for (i = 0; i < eet_readers_num; i++) | ||
696 | { | ||
697 | if (eet_readers[i]->references <= 0) | ||
698 | num++; | ||
699 | } | ||
700 | |||
701 | if (num > 0) | ||
702 | { | ||
703 | Eet_File **closelist = NULL; | ||
704 | |||
705 | closelist = alloca(num * sizeof(Eet_File *)); | ||
706 | num = 0; | ||
707 | for (i = 0; i < eet_writers_num; i++) | ||
708 | { | ||
709 | if (eet_writers[i]->references <= 0) | ||
710 | { | ||
711 | closelist[num] = eet_writers[i]; | ||
712 | eet_writers[i]->delete_me_now = 1; | ||
713 | num++; | ||
714 | } | ||
715 | } | ||
716 | |||
717 | for (i = 0; i < eet_readers_num; i++) | ||
718 | { | ||
719 | if (eet_readers[i]->references <= 0) | ||
720 | { | ||
721 | closelist[num] = eet_readers[i]; | ||
722 | eet_readers[i]->delete_me_now = 1; | ||
723 | num++; | ||
724 | } | ||
725 | } | ||
726 | |||
727 | for (i = 0; i < num; i++) | ||
728 | { | ||
729 | eet_internal_close(closelist[i], EINA_TRUE); | ||
730 | } | ||
731 | } | ||
732 | |||
733 | UNLOCK_CACHE; | ||
734 | } | ||
735 | |||
736 | /* FIXME: MMAP race condition in READ_WRITE_MODE */ | ||
737 | static Eet_File * | ||
738 | eet_internal_read2(Eet_File *ef) | ||
739 | { | ||
740 | const int *data = (const int *)ef->data; | ||
741 | const char *start = (const char *)ef->data; | ||
742 | int idx = 0; | ||
743 | unsigned long int bytes_directory_entries; | ||
744 | unsigned long int bytes_dictionary_entries; | ||
745 | unsigned long int signature_base_offset; | ||
746 | unsigned long int num_directory_entries; | ||
747 | unsigned long int num_dictionary_entries; | ||
748 | unsigned int i; | ||
749 | |||
750 | idx += sizeof(int); | ||
751 | if (eet_test_close((int)ntohl(*data) != EET_MAGIC_FILE2, ef)) | ||
752 | return NULL; | ||
753 | |||
754 | data++; | ||
755 | |||
756 | #define GET_INT(Value, Pointer, Index) \ | ||
757 | { \ | ||
758 | Value = ntohl(*Pointer); \ | ||
759 | Pointer++; \ | ||
760 | Index += sizeof(int); \ | ||
761 | } | ||
762 | |||
763 | /* get entries count and byte count */ | ||
764 | GET_INT(num_directory_entries, data, idx); | ||
765 | /* get dictionary count and byte count */ | ||
766 | GET_INT(num_dictionary_entries, data, idx); | ||
767 | |||
768 | bytes_directory_entries = EET_FILE2_DIRECTORY_ENTRY_SIZE * | ||
769 | num_directory_entries + EET_FILE2_HEADER_SIZE; | ||
770 | bytes_dictionary_entries = EET_FILE2_DICTIONARY_ENTRY_SIZE * | ||
771 | num_dictionary_entries; | ||
772 | |||
773 | /* we can't have > 0x7fffffff values here - invalid */ | ||
774 | if (eet_test_close((num_directory_entries > 0x7fffffff), ef)) | ||
775 | return NULL; | ||
776 | |||
777 | /* we can't have more bytes directory and bytes in dictionaries than the size of the file */ | ||
778 | if (eet_test_close((bytes_directory_entries + bytes_dictionary_entries) > | ||
779 | ef->data_size, ef)) | ||
780 | return NULL; | ||
781 | |||
782 | /* allocate header */ | ||
783 | ef->header = eet_file_header_calloc(1); | ||
784 | if (eet_test_close(!ef->header, ef)) | ||
785 | return NULL; | ||
786 | |||
787 | ef->header->magic = EET_MAGIC_FILE_HEADER; | ||
788 | |||
789 | /* allocate directory block in ram */ | ||
790 | ef->header->directory = eet_file_directory_calloc(1); | ||
791 | if (eet_test_close(!ef->header->directory, ef)) | ||
792 | return NULL; | ||
793 | |||
794 | /* 8 bit hash table (256 buckets) */ | ||
795 | ef->header->directory->size = 8; | ||
796 | /* allocate base hash table */ | ||
797 | ef->header->directory->nodes = | ||
798 | calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size)); | ||
799 | if (eet_test_close(!ef->header->directory->nodes, ef)) | ||
800 | return NULL; | ||
801 | |||
802 | signature_base_offset = 0; | ||
803 | if (num_directory_entries == 0) | ||
804 | { | ||
805 | signature_base_offset = ef->data_size; | ||
806 | } | ||
807 | |||
808 | /* actually read the directory block - all of it, into ram */ | ||
809 | for (i = 0; i < num_directory_entries; ++i) | ||
810 | { | ||
811 | const char *name; | ||
812 | Eet_File_Node *efn; | ||
813 | unsigned long int name_offset; | ||
814 | unsigned long int name_size; | ||
815 | int hash; | ||
816 | int flag; | ||
817 | |||
818 | /* out directory block is inconsistent - we have overrun our */ | ||
819 | /* dynamic block buffer before we finished scanning dir entries */ | ||
820 | efn = eet_file_node_malloc(1); | ||
821 | if (eet_test_close(!efn, ef)) | ||
822 | { | ||
823 | if (efn) eet_file_node_mp_free(efn); /* yes i know - we only get here if | ||
824 | * efn is null/0 -> trying to shut up | ||
825 | * warning tools like cppcheck */ | ||
826 | return NULL; | ||
827 | } | ||
828 | |||
829 | /* get entrie header */ | ||
830 | GET_INT(efn->offset, data, idx); | ||
831 | GET_INT(efn->size, data, idx); | ||
832 | GET_INT(efn->data_size, data, idx); | ||
833 | GET_INT(name_offset, data, idx); | ||
834 | GET_INT(name_size, data, idx); | ||
835 | GET_INT(flag, data, idx); | ||
836 | |||
837 | efn->compression = flag & 0x1 ? 1 : 0; | ||
838 | efn->ciphered = flag & 0x2 ? 1 : 0; | ||
839 | efn->alias = flag & 0x4 ? 1 : 0; | ||
840 | |||
841 | #define EFN_TEST(Test, Ef, Efn) \ | ||
842 | if (eet_test_close(Test, Ef)) \ | ||
843 | { \ | ||
844 | eet_file_node_mp_free(Efn); \ | ||
845 | return NULL; \ | ||
846 | } | ||
847 | |||
848 | /* check data pointer position */ | ||
849 | EFN_TEST(!((efn->size > 0) | ||
850 | && (efn->offset + efn->size <= ef->data_size) | ||
851 | && (efn->offset > bytes_dictionary_entries + | ||
852 | bytes_directory_entries)), ef, efn); | ||
853 | |||
854 | /* check name position */ | ||
855 | EFN_TEST(!((name_size > 0) | ||
856 | && (name_offset + name_size < ef->data_size) | ||
857 | && (name_offset >= bytes_dictionary_entries + | ||
858 | bytes_directory_entries)), ef, efn); | ||
859 | |||
860 | name = start + name_offset; | ||
861 | |||
862 | /* check '\0' at the end of name string */ | ||
863 | EFN_TEST(name[name_size - 1] != '\0', ef, efn); | ||
864 | |||
865 | efn->free_name = 0; | ||
866 | efn->name = (char *)name; | ||
867 | efn->name_size = name_size; | ||
868 | |||
869 | hash = _eet_hash_gen(efn->name, ef->header->directory->size); | ||
870 | efn->next = ef->header->directory->nodes[hash]; | ||
871 | ef->header->directory->nodes[hash] = efn; | ||
872 | |||
873 | /* read-only mode, so currently we have no data loaded */ | ||
874 | if (ef->mode == EET_FILE_MODE_READ) | ||
875 | efn->data = NULL; /* read-write mode - read everything into ram */ | ||
876 | else | ||
877 | { | ||
878 | efn->data = malloc(efn->size); | ||
879 | if (efn->data) | ||
880 | memcpy(efn->data, ef->data + efn->offset, efn->size); | ||
881 | } | ||
882 | |||
883 | /* compute the possible position of a signature */ | ||
884 | if (signature_base_offset < efn->offset + efn->size) | ||
885 | signature_base_offset = efn->offset + efn->size; | ||
886 | } | ||
887 | |||
888 | ef->ed = NULL; | ||
889 | |||
890 | if (num_dictionary_entries) | ||
891 | { | ||
892 | const int *dico = (const int *)ef->data + | ||
893 | EET_FILE2_DIRECTORY_ENTRY_COUNT * num_directory_entries + | ||
894 | EET_FILE2_HEADER_COUNT; | ||
895 | int j; | ||
896 | |||
897 | if (eet_test_close((num_dictionary_entries * | ||
898 | (int)EET_FILE2_DICTIONARY_ENTRY_SIZE + idx) > | ||
899 | (bytes_dictionary_entries + bytes_directory_entries), | ||
900 | ef)) | ||
901 | return NULL; | ||
902 | |||
903 | ef->ed = eet_dictionary_calloc(1); | ||
904 | if (eet_test_close(!ef->ed, ef)) | ||
905 | return NULL; | ||
906 | |||
907 | ef->ed->all = calloc(1, num_dictionary_entries * sizeof(Eet_String)); | ||
908 | if (eet_test_close(!ef->ed->all, ef)) | ||
909 | return NULL; | ||
910 | |||
911 | ef->ed->count = num_dictionary_entries; | ||
912 | ef->ed->total = num_dictionary_entries; | ||
913 | ef->ed->start = start + bytes_dictionary_entries + | ||
914 | bytes_directory_entries; | ||
915 | ef->ed->end = ef->ed->start; | ||
916 | |||
917 | for (j = 0; j < ef->ed->count; ++j) | ||
918 | { | ||
919 | unsigned int offset; | ||
920 | int hash; | ||
921 | |||
922 | GET_INT(hash, dico, idx); | ||
923 | GET_INT(offset, dico, idx); | ||
924 | GET_INT(ef->ed->all[j].len, dico, idx); | ||
925 | GET_INT(ef->ed->all[j].prev, dico, idx); | ||
926 | GET_INT(ef->ed->all[j].next, dico, idx); | ||
927 | |||
928 | /* Hash value could be stored on 8bits data, but this will break alignment of all the others data. | ||
929 | So stick to int and check the value. */ | ||
930 | if (eet_test_close(hash & 0xFFFFFF00, ef)) | ||
931 | return NULL; | ||
932 | |||
933 | /* Check string position */ | ||
934 | if (eet_test_close(!((ef->ed->all[j].len > 0) | ||
935 | && (offset > | ||
936 | (bytes_dictionary_entries + | ||
937 | bytes_directory_entries)) | ||
938 | && (offset + ef->ed->all[j].len < | ||
939 | ef->data_size)), ef)) | ||
940 | return NULL; | ||
941 | |||
942 | ef->ed->all[j].str = start + offset; | ||
943 | |||
944 | if (ef->ed->all[j].str + ef->ed->all[j].len > ef->ed->end) | ||
945 | ef->ed->end = ef->ed->all[j].str + ef->ed->all[j].len; | ||
946 | |||
947 | /* Check '\0' at the end of the string */ | ||
948 | if (eet_test_close(ef->ed->all[j].str[ef->ed->all[j].len - 1] != | ||
949 | '\0', ef)) | ||
950 | return NULL; | ||
951 | |||
952 | ef->ed->all[j].hash = hash; | ||
953 | if (ef->ed->all[j].prev == -1) | ||
954 | ef->ed->hash[hash] = j; | ||
955 | |||
956 | /* compute the possible position of a signature */ | ||
957 | if (signature_base_offset < offset + ef->ed->all[j].len) | ||
958 | signature_base_offset = offset + ef->ed->all[j].len; | ||
959 | } | ||
960 | } | ||
961 | |||
962 | /* Check if the file is signed */ | ||
963 | ef->x509_der = NULL; | ||
964 | ef->x509_length = 0; | ||
965 | ef->signature = NULL; | ||
966 | ef->signature_length = 0; | ||
967 | |||
968 | if (signature_base_offset < ef->data_size) | ||
969 | { | ||
970 | #ifdef HAVE_SIGNATURE | ||
971 | const unsigned char *buffer = ((const unsigned char *)ef->data) + | ||
972 | signature_base_offset; | ||
973 | ef->x509_der = eet_identity_check(ef->data, | ||
974 | signature_base_offset, | ||
975 | &ef->sha1, | ||
976 | &ef->sha1_length, | ||
977 | buffer, | ||
978 | ef->data_size - signature_base_offset, | ||
979 | &ef->signature, | ||
980 | &ef->signature_length, | ||
981 | &ef->x509_length); | ||
982 | |||
983 | if (eet_test_close(!ef->x509_der, ef)) | ||
984 | return NULL; | ||
985 | |||
986 | #else /* ifdef HAVE_SIGNATURE */ | ||
987 | ERR( | ||
988 | "This file could be signed but you didn't compile the necessary code to check the signature."); | ||
989 | #endif /* ifdef HAVE_SIGNATURE */ | ||
990 | } | ||
991 | |||
992 | return ef; | ||
993 | } | ||
994 | |||
995 | #if EET_OLD_EET_FILE_FORMAT | ||
996 | static Eet_File * | ||
997 | eet_internal_read1(Eet_File *ef) | ||
998 | { | ||
999 | const unsigned char *dyn_buf = NULL; | ||
1000 | const unsigned char *p = NULL; | ||
1001 | unsigned long int byte_entries; | ||
1002 | unsigned long int num_entries; | ||
1003 | unsigned int i; | ||
1004 | int idx = 0; | ||
1005 | |||
1006 | WRN( | ||
1007 | "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.", | ||
1008 | ef->path); | ||
1009 | |||
1010 | /* build header table if read mode */ | ||
1011 | /* geat header */ | ||
1012 | idx += sizeof(int); | ||
1013 | if (eet_test_close((int)ntohl(*((int *)ef->data)) != EET_MAGIC_FILE, ef)) | ||
1014 | return NULL; | ||
1015 | |||
1016 | #define EXTRACT_INT(Value, Pointer, Index) \ | ||
1017 | { \ | ||
1018 | int tmp; \ | ||
1019 | memcpy(&tmp, Pointer + Index, sizeof(int)); \ | ||
1020 | Value = ntohl(tmp); \ | ||
1021 | Index += sizeof(int); \ | ||
1022 | } | ||
1023 | |||
1024 | /* get entries count and byte count */ | ||
1025 | EXTRACT_INT(num_entries, ef->data, idx); | ||
1026 | EXTRACT_INT(byte_entries, ef->data, idx); | ||
1027 | |||
1028 | /* we can't have <= 0 values here - invalid */ | ||
1029 | if (eet_test_close((num_entries > 0x7fffffff) || | ||
1030 | (byte_entries > 0x7fffffff), ef)) | ||
1031 | return NULL; | ||
1032 | |||
1033 | /* we can't have more entires than minimum bytes for those! invalid! */ | ||
1034 | if (eet_test_close((num_entries * 20) > byte_entries, ef)) | ||
1035 | return NULL; | ||
1036 | |||
1037 | /* check we will not outrun the file limit */ | ||
1038 | if (eet_test_close(((byte_entries + (int)(sizeof(int) * 3)) > | ||
1039 | ef->data_size), ef)) | ||
1040 | return NULL; | ||
1041 | |||
1042 | /* allocate header */ | ||
1043 | ef->header = eet_file_header_calloc(1); | ||
1044 | if (eet_test_close(!ef->header, ef)) | ||
1045 | return NULL; | ||
1046 | |||
1047 | ef->header->magic = EET_MAGIC_FILE_HEADER; | ||
1048 | |||
1049 | /* allocate directory block in ram */ | ||
1050 | ef->header->directory = eet_file_directory_calloc(1); | ||
1051 | if (eet_test_close(!ef->header->directory, ef)) | ||
1052 | return NULL; | ||
1053 | |||
1054 | /* 8 bit hash table (256 buckets) */ | ||
1055 | ef->header->directory->size = 8; | ||
1056 | /* allocate base hash table */ | ||
1057 | ef->header->directory->nodes = | ||
1058 | calloc(1, sizeof(Eet_File_Node *) * (1 << ef->header->directory->size)); | ||
1059 | if (eet_test_close(!ef->header->directory->nodes, ef)) | ||
1060 | return NULL; | ||
1061 | |||
1062 | /* actually read the directory block - all of it, into ram */ | ||
1063 | dyn_buf = ef->data + idx; | ||
1064 | |||
1065 | /* parse directory block */ | ||
1066 | p = dyn_buf; | ||
1067 | |||
1068 | for (i = 0; i < num_entries; i++) | ||
1069 | { | ||
1070 | Eet_File_Node *efn; | ||
1071 | void *data = NULL; | ||
1072 | int indexn = 0; | ||
1073 | int name_size; | ||
1074 | int hash; | ||
1075 | int k; | ||
1076 | |||
1077 | #define HEADER_SIZE (sizeof(int) * 5) | ||
1078 | |||
1079 | /* out directory block is inconsistent - we have overrun our */ | ||
1080 | /* dynamic block buffer before we finished scanning dir entries */ | ||
1081 | if (eet_test_close(p + HEADER_SIZE >= (dyn_buf + byte_entries), ef)) | ||
1082 | return NULL; | ||
1083 | |||
1084 | /* allocate all the ram needed for this stored node accounting */ | ||
1085 | efn = eet_file_node_malloc(1); | ||
1086 | if (eet_test_close(!efn, ef)) | ||
1087 | { | ||
1088 | if (efn) eet_file_node_mp_free(efn); /* yes i know - we only get here if | ||
1089 | * efn is null/0 -> trying to shut up | ||
1090 | * warning tools like cppcheck */ | ||
1091 | return NULL; | ||
1092 | } | ||
1093 | |||
1094 | /* get entrie header */ | ||
1095 | EXTRACT_INT(efn->offset, p, indexn); | ||
1096 | EXTRACT_INT(efn->compression, p, indexn); | ||
1097 | EXTRACT_INT(efn->size, p, indexn); | ||
1098 | EXTRACT_INT(efn->data_size, p, indexn); | ||
1099 | EXTRACT_INT(name_size, p, indexn); | ||
1100 | |||
1101 | efn->name_size = name_size; | ||
1102 | efn->ciphered = 0; | ||
1103 | efn->alias = 0; | ||
1104 | |||
1105 | /* invalid size */ | ||
1106 | if (eet_test_close(efn->size <= 0, ef)) | ||
1107 | { | ||
1108 | eet_file_node_mp_free(efn); | ||
1109 | return NULL; | ||
1110 | } | ||
1111 | |||
1112 | /* invalid name_size */ | ||
1113 | if (eet_test_close(name_size <= 0, ef)) | ||
1114 | { | ||
1115 | eet_file_node_mp_free(efn); | ||
1116 | return NULL; | ||
1117 | } | ||
1118 | |||
1119 | /* reading name would mean falling off end of dyn_buf - invalid */ | ||
1120 | if (eet_test_close((p + 16 + name_size) > (dyn_buf + byte_entries), ef)) | ||
1121 | { | ||
1122 | eet_file_node_mp_free(efn); | ||
1123 | return NULL; | ||
1124 | } | ||
1125 | |||
1126 | /* This code is useless if we dont want backward compatibility */ | ||
1127 | for (k = name_size; | ||
1128 | k > 0 && ((unsigned char)*(p + HEADER_SIZE + k)) != 0; --k) | ||
1129 | ; | ||
1130 | |||
1131 | efn->free_name = ((unsigned char)*(p + HEADER_SIZE + k)) != 0; | ||
1132 | |||
1133 | if (efn->free_name) | ||
1134 | { | ||
1135 | efn->name = malloc(sizeof(char) * name_size + 1); | ||
1136 | if (eet_test_close(!efn->name, ef)) | ||
1137 | { | ||
1138 | eet_file_node_mp_free(efn); | ||
1139 | return NULL; | ||
1140 | } | ||
1141 | |||
1142 | strncpy(efn->name, (char *)p + HEADER_SIZE, name_size); | ||
1143 | efn->name[name_size] = 0; | ||
1144 | |||
1145 | WRN( | ||
1146 | "File: %s is not up to date for key \"%s\" - needs rebuilding sometime", | ||
1147 | ef->path, | ||
1148 | efn->name); | ||
1149 | } | ||
1150 | else | ||
1151 | /* The only really useful peace of code for efn->name (no backward compatibility) */ | ||
1152 | efn->name = (char *)((unsigned char *)(p + HEADER_SIZE)); | ||
1153 | |||
1154 | /* get hash bucket it should go in */ | ||
1155 | hash = _eet_hash_gen(efn->name, ef->header->directory->size); | ||
1156 | efn->next = ef->header->directory->nodes[hash]; | ||
1157 | ef->header->directory->nodes[hash] = efn; | ||
1158 | |||
1159 | /* read-only mode, so currently we have no data loaded */ | ||
1160 | if (ef->mode == EET_FILE_MODE_READ) | ||
1161 | efn->data = NULL; /* read-write mode - read everything into ram */ | ||
1162 | else | ||
1163 | { | ||
1164 | data = malloc(efn->size); | ||
1165 | if (data) | ||
1166 | memcpy(data, ef->data + efn->offset, efn->size); | ||
1167 | |||
1168 | efn->data = data; | ||
1169 | } | ||
1170 | |||
1171 | /* advance */ | ||
1172 | p += HEADER_SIZE + name_size; | ||
1173 | } | ||
1174 | return ef; | ||
1175 | } | ||
1176 | |||
1177 | #endif /* if EET_OLD_EET_FILE_FORMAT */ | ||
1178 | |||
1179 | /* | ||
1180 | * this should only be called when the cache lock is already held | ||
1181 | * (We could drop this restriction if we add a parameter to eet_test_close | ||
1182 | * that indicates if the lock is held or not. For now it is easiest | ||
1183 | * to just require that it is always held.) | ||
1184 | */ | ||
1185 | static Eet_File * | ||
1186 | eet_internal_read(Eet_File *ef) | ||
1187 | { | ||
1188 | const int *data = (const int *)ef->data; | ||
1189 | |||
1190 | if (eet_test_close((ef->data == (void *)-1) || (!ef->data), ef)) | ||
1191 | return NULL; | ||
1192 | |||
1193 | if (eet_test_close(ef->data_size < (int)sizeof(int) * 3, ef)) | ||
1194 | return NULL; | ||
1195 | |||
1196 | switch (ntohl(*data)) | ||
1197 | { | ||
1198 | #if EET_OLD_EET_FILE_FORMAT | ||
1199 | case EET_MAGIC_FILE: | ||
1200 | return eet_internal_read1(ef); | ||
1201 | |||
1202 | #endif /* if EET_OLD_EET_FILE_FORMAT */ | ||
1203 | case EET_MAGIC_FILE2: | ||
1204 | return eet_internal_read2(ef); | ||
1205 | |||
1206 | default: | ||
1207 | ef->delete_me_now = 1; | ||
1208 | eet_internal_close(ef, EINA_TRUE); | ||
1209 | break; | ||
1210 | } | ||
1211 | |||
1212 | return NULL; | ||
1213 | } | ||
1214 | |||
1215 | static Eet_Error | ||
1216 | eet_internal_close(Eet_File *ef, | ||
1217 | Eina_Bool locked) | ||
1218 | { | ||
1219 | Eet_Error err; | ||
1220 | |||
1221 | /* check to see its' an eet file pointer */ | ||
1222 | if (eet_check_pointer(ef)) | ||
1223 | return EET_ERROR_BAD_OBJECT; | ||
1224 | |||
1225 | if (!locked) | ||
1226 | LOCK_CACHE; | ||
1227 | |||
1228 | /* deref */ | ||
1229 | ef->references--; | ||
1230 | /* if its still referenced - dont go any further */ | ||
1231 | if (ef->references > 0) | ||
1232 | { | ||
1233 | /* flush any writes */ | ||
1234 | if ((ef->mode == EET_FILE_MODE_WRITE) || | ||
1235 | (ef->mode == EET_FILE_MODE_READ_WRITE)) | ||
1236 | eet_sync(ef); | ||
1237 | goto on_error; | ||
1238 | } | ||
1239 | |||
1240 | err = eet_flush2(ef); | ||
1241 | |||
1242 | eet_identity_unref(ef->key); | ||
1243 | ef->key = NULL; | ||
1244 | |||
1245 | /* if not urgent to delete it - dont free it - leave it in cache */ | ||
1246 | if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ)) | ||
1247 | goto on_error; | ||
1248 | |||
1249 | /* remove from cache */ | ||
1250 | if (ef->mode == EET_FILE_MODE_READ) | ||
1251 | eet_cache_del(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); | ||
1252 | else if ((ef->mode == EET_FILE_MODE_WRITE) || | ||
1253 | (ef->mode == EET_FILE_MODE_READ_WRITE)) | ||
1254 | eet_cache_del(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); | ||
1255 | |||
1256 | /* we can unlock the cache now */ | ||
1257 | if (!locked) | ||
1258 | UNLOCK_CACHE; | ||
1259 | |||
1260 | DESTROY_FILE(ef); | ||
1261 | |||
1262 | /* free up data */ | ||
1263 | if (ef->header) | ||
1264 | { | ||
1265 | if (ef->header->directory) | ||
1266 | { | ||
1267 | if (ef->header->directory->nodes) | ||
1268 | { | ||
1269 | int i, num; | ||
1270 | |||
1271 | num = (1 << ef->header->directory->size); | ||
1272 | for (i = 0; i < num; i++) | ||
1273 | { | ||
1274 | Eet_File_Node *efn; | ||
1275 | |||
1276 | while ((efn = ef->header->directory->nodes[i])) | ||
1277 | { | ||
1278 | if (efn->data) | ||
1279 | free(efn->data); | ||
1280 | |||
1281 | ef->header->directory->nodes[i] = efn->next; | ||
1282 | |||
1283 | if (efn->free_name) | ||
1284 | free(efn->name); | ||
1285 | |||
1286 | eet_file_node_mp_free(efn); | ||
1287 | } | ||
1288 | } | ||
1289 | free(ef->header->directory->nodes); | ||
1290 | } | ||
1291 | |||
1292 | eet_file_directory_mp_free(ef->header->directory); | ||
1293 | } | ||
1294 | |||
1295 | eet_file_header_mp_free(ef->header); | ||
1296 | } | ||
1297 | |||
1298 | eet_dictionary_free(ef->ed); | ||
1299 | |||
1300 | if (ef->sha1) | ||
1301 | free(ef->sha1); | ||
1302 | |||
1303 | if (ef->readfp) | ||
1304 | { | ||
1305 | if (ef->data) | ||
1306 | eina_file_map_free(ef->readfp, (void *)ef->data); | ||
1307 | |||
1308 | eina_file_close(ef->readfp); | ||
1309 | } | ||
1310 | |||
1311 | /* zero out ram for struct - caution tactic against stale memory use */ | ||
1312 | memset(ef, 0, sizeof(Eet_File)); | ||
1313 | |||
1314 | /* free it */ | ||
1315 | eina_stringshare_del(ef->path); | ||
1316 | eet_file_mp_free(ef); | ||
1317 | return err; | ||
1318 | |||
1319 | on_error: | ||
1320 | if (!locked) | ||
1321 | UNLOCK_CACHE; | ||
1322 | |||
1323 | return EET_ERROR_NONE; | ||
1324 | } | ||
1325 | |||
1326 | EAPI Eet_File * | ||
1327 | eet_memopen_read(const void *data, | ||
1328 | size_t size) | ||
1329 | { | ||
1330 | Eet_File *ef; | ||
1331 | |||
1332 | if (!data || size == 0) | ||
1333 | return NULL; | ||
1334 | |||
1335 | ef = eet_file_malloc(1); | ||
1336 | if (!ef) | ||
1337 | return NULL; | ||
1338 | |||
1339 | INIT_FILE(ef); | ||
1340 | ef->ed = NULL; | ||
1341 | ef->path = NULL; | ||
1342 | ef->key = NULL; | ||
1343 | ef->magic = EET_MAGIC_FILE; | ||
1344 | ef->references = 1; | ||
1345 | ef->mode = EET_FILE_MODE_READ; | ||
1346 | ef->header = NULL; | ||
1347 | ef->delete_me_now = 1; | ||
1348 | ef->readfp = NULL; | ||
1349 | ef->data = data; | ||
1350 | ef->data_size = size; | ||
1351 | ef->sha1 = NULL; | ||
1352 | ef->sha1_length = 0; | ||
1353 | |||
1354 | /* eet_internal_read expects the cache lock to be held when it is called */ | ||
1355 | LOCK_CACHE; | ||
1356 | ef = eet_internal_read(ef); | ||
1357 | UNLOCK_CACHE; | ||
1358 | return ef; | ||
1359 | } | ||
1360 | |||
1361 | EAPI const char * | ||
1362 | eet_file_get(Eet_File *ef) | ||
1363 | { | ||
1364 | if (eet_check_pointer(ef)) return NULL; | ||
1365 | return ef->path; | ||
1366 | } | ||
1367 | |||
1368 | EAPI Eet_File * | ||
1369 | eet_open(const char *file, | ||
1370 | Eet_File_Mode mode) | ||
1371 | { | ||
1372 | Eina_File *fp; | ||
1373 | Eet_File *ef; | ||
1374 | int file_len; | ||
1375 | unsigned long int size; | ||
1376 | |||
1377 | if (!file) | ||
1378 | return NULL; | ||
1379 | |||
1380 | /* find the current file handle in cache*/ | ||
1381 | ef = NULL; | ||
1382 | LOCK_CACHE; | ||
1383 | if (mode == EET_FILE_MODE_READ) | ||
1384 | { | ||
1385 | ef = eet_cache_find((char *)file, eet_writers, eet_writers_num); | ||
1386 | if (ef) | ||
1387 | { | ||
1388 | eet_sync(ef); | ||
1389 | ef->references++; | ||
1390 | ef->delete_me_now = 1; | ||
1391 | eet_internal_close(ef, EINA_TRUE); | ||
1392 | } | ||
1393 | |||
1394 | ef = eet_cache_find((char *)file, eet_readers, eet_readers_num); | ||
1395 | } | ||
1396 | else if ((mode == EET_FILE_MODE_WRITE) || | ||
1397 | (mode == EET_FILE_MODE_READ_WRITE)) | ||
1398 | { | ||
1399 | ef = eet_cache_find((char *)file, eet_readers, eet_readers_num); | ||
1400 | if (ef) | ||
1401 | { | ||
1402 | ef->delete_me_now = 1; | ||
1403 | ef->references++; | ||
1404 | eet_internal_close(ef, EINA_TRUE); | ||
1405 | } | ||
1406 | |||
1407 | ef = eet_cache_find((char *)file, eet_writers, eet_writers_num); | ||
1408 | } | ||
1409 | |||
1410 | /* try open the file based on mode */ | ||
1411 | if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE)) | ||
1412 | { | ||
1413 | /* Prevent garbage in futur comparison. */ | ||
1414 | fp = eina_file_open(file, EINA_FALSE); | ||
1415 | if (!fp) | ||
1416 | goto open_error; | ||
1417 | |||
1418 | size = eina_file_size_get(fp); | ||
1419 | |||
1420 | if (size < ((int)sizeof(int) * 3)) | ||
1421 | { | ||
1422 | eina_file_close(fp); | ||
1423 | fp = NULL; | ||
1424 | |||
1425 | size = 0; | ||
1426 | |||
1427 | goto open_error; | ||
1428 | } | ||
1429 | |||
1430 | open_error: | ||
1431 | if (!fp && mode == EET_FILE_MODE_READ) | ||
1432 | goto on_error; | ||
1433 | } | ||
1434 | else | ||
1435 | { | ||
1436 | if (mode != EET_FILE_MODE_WRITE) | ||
1437 | return NULL; | ||
1438 | |||
1439 | size = 0; | ||
1440 | |||
1441 | fp = NULL; | ||
1442 | } | ||
1443 | |||
1444 | /* We found one */ | ||
1445 | if (ef && ef->readfp != fp) | ||
1446 | { | ||
1447 | ef->delete_me_now = 1; | ||
1448 | ef->references++; | ||
1449 | eet_internal_close(ef, EINA_TRUE); | ||
1450 | ef = NULL; | ||
1451 | } | ||
1452 | |||
1453 | if (ef) | ||
1454 | { | ||
1455 | /* reference it up and return it */ | ||
1456 | if (fp) | ||
1457 | eina_file_close(fp); | ||
1458 | |||
1459 | ef->references++; | ||
1460 | UNLOCK_CACHE; | ||
1461 | return ef; | ||
1462 | } | ||
1463 | |||
1464 | file_len = strlen(file) + 1; | ||
1465 | |||
1466 | /* Allocate struct for eet file and have it zero'd out */ | ||
1467 | ef = eet_file_malloc(1); | ||
1468 | if (!ef) | ||
1469 | goto on_error; | ||
1470 | |||
1471 | /* fill some of the members */ | ||
1472 | INIT_FILE(ef); | ||
1473 | ef->key = NULL; | ||
1474 | ef->readfp = fp; | ||
1475 | ef->path = eina_stringshare_add_length(file, file_len); | ||
1476 | ef->magic = EET_MAGIC_FILE; | ||
1477 | ef->references = 1; | ||
1478 | ef->mode = mode; | ||
1479 | ef->header = NULL; | ||
1480 | ef->writes_pending = 0; | ||
1481 | ef->delete_me_now = 0; | ||
1482 | ef->data = NULL; | ||
1483 | ef->data_size = 0; | ||
1484 | ef->sha1 = NULL; | ||
1485 | ef->sha1_length = 0; | ||
1486 | |||
1487 | ef->ed = (mode == EET_FILE_MODE_WRITE) | ||
1488 | || (!ef->readfp && mode == EET_FILE_MODE_READ_WRITE) ? | ||
1489 | eet_dictionary_add() : NULL; | ||
1490 | |||
1491 | if (!ef->readfp && | ||
1492 | (mode == EET_FILE_MODE_READ_WRITE || mode == EET_FILE_MODE_WRITE)) | ||
1493 | goto empty_file; | ||
1494 | |||
1495 | /* if we can't open - bail out */ | ||
1496 | if (eet_test_close(!ef->readfp, ef)) | ||
1497 | goto on_error; | ||
1498 | |||
1499 | /* if we opened for read or read-write */ | ||
1500 | if ((mode == EET_FILE_MODE_READ) || (mode == EET_FILE_MODE_READ_WRITE)) | ||
1501 | { | ||
1502 | ef->data_size = size; | ||
1503 | ef->data = eina_file_map_all(fp, EINA_FILE_SEQUENTIAL); | ||
1504 | if (eet_test_close((ef->data == NULL), ef)) | ||
1505 | goto on_error; | ||
1506 | |||
1507 | ef = eet_internal_read(ef); | ||
1508 | if (!ef) | ||
1509 | goto on_error; | ||
1510 | } | ||
1511 | |||
1512 | empty_file: | ||
1513 | /* add to cache */ | ||
1514 | if (ef->references == 1) | ||
1515 | { | ||
1516 | if (ef->mode == EET_FILE_MODE_READ) | ||
1517 | eet_cache_add(ef, &eet_readers, &eet_readers_num, &eet_readers_alloc); | ||
1518 | else if ((ef->mode == EET_FILE_MODE_WRITE) || | ||
1519 | (ef->mode == EET_FILE_MODE_READ_WRITE)) | ||
1520 | eet_cache_add(ef, &eet_writers, &eet_writers_num, &eet_writers_alloc); | ||
1521 | } | ||
1522 | |||
1523 | UNLOCK_CACHE; | ||
1524 | return ef; | ||
1525 | |||
1526 | on_error: | ||
1527 | UNLOCK_CACHE; | ||
1528 | return NULL; | ||
1529 | } | ||
1530 | |||
1531 | EAPI Eet_File_Mode | ||
1532 | eet_mode_get(Eet_File *ef) | ||
1533 | { | ||
1534 | /* check to see its' an eet file pointer */ | ||
1535 | if ((!ef) || (ef->magic != EET_MAGIC_FILE)) | ||
1536 | return EET_FILE_MODE_INVALID; | ||
1537 | else | ||
1538 | return ef->mode; | ||
1539 | } | ||
1540 | |||
1541 | EAPI const void * | ||
1542 | eet_identity_x509(Eet_File *ef, | ||
1543 | int *der_length) | ||
1544 | { | ||
1545 | if (!ef->x509_der) | ||
1546 | return NULL; | ||
1547 | |||
1548 | if (der_length) | ||
1549 | *der_length = ef->x509_length; | ||
1550 | |||
1551 | return ef->x509_der; | ||
1552 | } | ||
1553 | |||
1554 | EAPI const void * | ||
1555 | eet_identity_signature(Eet_File *ef, | ||
1556 | int *signature_length) | ||
1557 | { | ||
1558 | if (!ef->signature) | ||
1559 | return NULL; | ||
1560 | |||
1561 | if (signature_length) | ||
1562 | *signature_length = ef->signature_length; | ||
1563 | |||
1564 | return ef->signature; | ||
1565 | } | ||
1566 | |||
1567 | EAPI const void * | ||
1568 | eet_identity_sha1(Eet_File *ef, | ||
1569 | int *sha1_length) | ||
1570 | { | ||
1571 | if (!ef->sha1) | ||
1572 | ef->sha1 = eet_identity_compute_sha1(ef->data, | ||
1573 | ef->data_size, | ||
1574 | &ef->sha1_length); | ||
1575 | |||
1576 | if (sha1_length) | ||
1577 | *sha1_length = ef->sha1_length; | ||
1578 | |||
1579 | return ef->sha1; | ||
1580 | } | ||
1581 | |||
1582 | EAPI Eet_Error | ||
1583 | eet_identity_set(Eet_File *ef, | ||
1584 | Eet_Key *key) | ||
1585 | { | ||
1586 | Eet_Key *tmp; | ||
1587 | |||
1588 | if (!ef) | ||
1589 | return EET_ERROR_BAD_OBJECT; | ||
1590 | |||
1591 | tmp = ef->key; | ||
1592 | ef->key = key; | ||
1593 | eet_identity_ref(ef->key); | ||
1594 | eet_identity_unref(tmp); | ||
1595 | |||
1596 | /* flags that writes are pending */ | ||
1597 | ef->writes_pending = 1; | ||
1598 | |||
1599 | return EET_ERROR_NONE; | ||
1600 | } | ||
1601 | |||
1602 | EAPI Eet_Error | ||
1603 | eet_close(Eet_File *ef) | ||
1604 | { | ||
1605 | return eet_internal_close(ef, EINA_FALSE); | ||
1606 | } | ||
1607 | |||
1608 | EAPI void * | ||
1609 | eet_read_cipher(Eet_File *ef, | ||
1610 | const char *name, | ||
1611 | int *size_ret, | ||
1612 | const char *cipher_key) | ||
1613 | { | ||
1614 | Eet_File_Node *efn; | ||
1615 | char *data = NULL; | ||
1616 | unsigned long int size = 0; | ||
1617 | |||
1618 | if (size_ret) | ||
1619 | *size_ret = 0; | ||
1620 | |||
1621 | /* check to see its' an eet file pointer */ | ||
1622 | if (eet_check_pointer(ef)) | ||
1623 | return NULL; | ||
1624 | |||
1625 | if (!name) | ||
1626 | return NULL; | ||
1627 | |||
1628 | if ((ef->mode != EET_FILE_MODE_READ) && | ||
1629 | (ef->mode != EET_FILE_MODE_READ_WRITE)) | ||
1630 | return NULL; | ||
1631 | |||
1632 | /* no header, return NULL */ | ||
1633 | if (eet_check_header(ef)) | ||
1634 | return NULL; | ||
1635 | |||
1636 | LOCK_FILE(ef); | ||
1637 | |||
1638 | /* hunt hash bucket */ | ||
1639 | efn = find_node_by_name(ef, name); | ||
1640 | if (!efn) | ||
1641 | goto on_error; | ||
1642 | |||
1643 | /* get size (uncompressed, if compressed at all) */ | ||
1644 | size = efn->data_size; | ||
1645 | |||
1646 | /* allocate data */ | ||
1647 | data = malloc(size); | ||
1648 | if (!data) | ||
1649 | goto on_error; | ||
1650 | |||
1651 | /* uncompressed data */ | ||
1652 | if (efn->compression == 0) | ||
1653 | { | ||
1654 | void *data_deciphered = NULL; | ||
1655 | unsigned int data_deciphered_sz = 0; | ||
1656 | /* if we already have the data in ram... copy that */ | ||
1657 | |||
1658 | if (efn->ciphered && efn->size > size) | ||
1659 | { | ||
1660 | size = efn->size; | ||
1661 | data = realloc(data, efn->size); | ||
1662 | } | ||
1663 | |||
1664 | if (efn->data) | ||
1665 | memcpy(data, efn->data, size); | ||
1666 | else | ||
1667 | if (!read_data_from_disk(ef, efn, data, size)) | ||
1668 | goto on_error; | ||
1669 | |||
1670 | if (efn->ciphered && cipher_key) | ||
1671 | { | ||
1672 | if (eet_decipher(data, efn->size, cipher_key, strlen(cipher_key), | ||
1673 | &data_deciphered, &data_deciphered_sz)) | ||
1674 | { | ||
1675 | if (data_deciphered) | ||
1676 | free(data_deciphered); | ||
1677 | |||
1678 | goto on_error; | ||
1679 | } | ||
1680 | |||
1681 | free(data); | ||
1682 | data = data_deciphered; | ||
1683 | size = data_deciphered_sz; | ||
1684 | } | ||
1685 | } | ||
1686 | /* compressed data */ | ||
1687 | else | ||
1688 | { | ||
1689 | void *tmp_data = NULL; | ||
1690 | void *data_deciphered = NULL; | ||
1691 | unsigned int data_deciphered_sz = 0; | ||
1692 | int free_tmp = 0; | ||
1693 | int compr_size = efn->size; | ||
1694 | uLongf dlen; | ||
1695 | |||
1696 | /* if we already have the data in ram... copy that */ | ||
1697 | if (efn->data) | ||
1698 | tmp_data = efn->data; | ||
1699 | else | ||
1700 | { | ||
1701 | tmp_data = malloc(compr_size); | ||
1702 | if (!tmp_data) | ||
1703 | goto on_error; | ||
1704 | |||
1705 | free_tmp = 1; | ||
1706 | |||
1707 | if (!read_data_from_disk(ef, efn, tmp_data, compr_size)) | ||
1708 | { | ||
1709 | free(tmp_data); | ||
1710 | goto on_error; | ||
1711 | } | ||
1712 | } | ||
1713 | |||
1714 | if (efn->ciphered && cipher_key) | ||
1715 | { | ||
1716 | if (eet_decipher(tmp_data, compr_size, cipher_key, | ||
1717 | strlen(cipher_key), &data_deciphered, | ||
1718 | &data_deciphered_sz)) | ||
1719 | { | ||
1720 | if (free_tmp) | ||
1721 | free(tmp_data); | ||
1722 | |||
1723 | if (data_deciphered) | ||
1724 | free(data_deciphered); | ||
1725 | |||
1726 | goto on_error; | ||
1727 | } | ||
1728 | |||
1729 | if (free_tmp) | ||
1730 | free(tmp_data); | ||
1731 | free_tmp = 1; | ||
1732 | tmp_data = data_deciphered; | ||
1733 | compr_size = data_deciphered_sz; | ||
1734 | } | ||
1735 | |||
1736 | /* decompress it */ | ||
1737 | dlen = size; | ||
1738 | if (uncompress((Bytef *)data, &dlen, | ||
1739 | tmp_data, (uLongf)compr_size)) | ||
1740 | { | ||
1741 | if (free_tmp) | ||
1742 | free(tmp_data); | ||
1743 | goto on_error; | ||
1744 | } | ||
1745 | |||
1746 | if (free_tmp) | ||
1747 | free(tmp_data); | ||
1748 | } | ||
1749 | |||
1750 | UNLOCK_FILE(ef); | ||
1751 | |||
1752 | /* handle alias */ | ||
1753 | if (efn->alias) | ||
1754 | { | ||
1755 | void *tmp; | ||
1756 | |||
1757 | if (data[size - 1] != '\0') | ||
1758 | goto on_error; | ||
1759 | |||
1760 | tmp = eet_read_cipher(ef, data, size_ret, cipher_key); | ||
1761 | |||
1762 | free(data); | ||
1763 | |||
1764 | data = tmp; | ||
1765 | } | ||
1766 | else | ||
1767 | /* fill in return values */ | ||
1768 | if (size_ret) | ||
1769 | *size_ret = size; | ||
1770 | |||
1771 | return data; | ||
1772 | |||
1773 | on_error: | ||
1774 | UNLOCK_FILE(ef); | ||
1775 | free(data); | ||
1776 | return NULL; | ||
1777 | } | ||
1778 | |||
1779 | EAPI void * | ||
1780 | eet_read(Eet_File *ef, | ||
1781 | const char *name, | ||
1782 | int *size_ret) | ||
1783 | { | ||
1784 | return eet_read_cipher(ef, name, size_ret, NULL); | ||
1785 | } | ||
1786 | |||
1787 | EAPI const void * | ||
1788 | eet_read_direct(Eet_File *ef, | ||
1789 | const char *name, | ||
1790 | int *size_ret) | ||
1791 | { | ||
1792 | Eet_File_Node *efn; | ||
1793 | const char *data = NULL; | ||
1794 | int size = 0; | ||
1795 | |||
1796 | if (size_ret) | ||
1797 | *size_ret = 0; | ||
1798 | |||
1799 | /* check to see its' an eet file pointer */ | ||
1800 | if (eet_check_pointer(ef)) | ||
1801 | return NULL; | ||
1802 | |||
1803 | if (!name) | ||
1804 | return NULL; | ||
1805 | |||
1806 | if ((ef->mode != EET_FILE_MODE_READ) && | ||
1807 | (ef->mode != EET_FILE_MODE_READ_WRITE)) | ||
1808 | return NULL; | ||
1809 | |||
1810 | /* no header, return NULL */ | ||
1811 | if (eet_check_header(ef)) | ||
1812 | return NULL; | ||
1813 | |||
1814 | LOCK_FILE(ef); | ||
1815 | |||
1816 | /* hunt hash bucket */ | ||
1817 | efn = find_node_by_name(ef, name); | ||
1818 | if (!efn) | ||
1819 | goto on_error; | ||
1820 | |||
1821 | /* trick to detect data in memory instead of mmaped from disk */ | ||
1822 | if (efn->offset > ef->data_size && !efn->data) | ||
1823 | goto on_error; | ||
1824 | |||
1825 | /* get size (uncompressed, if compressed at all) */ | ||
1826 | size = efn->data_size; | ||
1827 | |||
1828 | if (efn->alias) | ||
1829 | { | ||
1830 | data = efn->data ? efn->data : ef->data + efn->offset; | ||
1831 | |||
1832 | /* handle alias case */ | ||
1833 | if (efn->compression) | ||
1834 | { | ||
1835 | char *tmp; | ||
1836 | int compr_size = efn->size; | ||
1837 | uLongf dlen; | ||
1838 | |||
1839 | tmp = alloca(sizeof (compr_size)); | ||
1840 | dlen = size; | ||
1841 | |||
1842 | if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data, | ||
1843 | (uLongf)compr_size)) | ||
1844 | goto on_error; | ||
1845 | |||
1846 | if (tmp[compr_size - 1] != '\0') | ||
1847 | goto on_error; | ||
1848 | |||
1849 | UNLOCK_FILE(ef); | ||
1850 | |||
1851 | return eet_read_direct(ef, tmp, size_ret); | ||
1852 | } | ||
1853 | |||
1854 | if (!data) | ||
1855 | goto on_error; | ||
1856 | |||
1857 | if (data[size - 1] != '\0') | ||
1858 | goto on_error; | ||
1859 | |||
1860 | UNLOCK_FILE(ef); | ||
1861 | |||
1862 | return eet_read_direct(ef, data, size_ret); | ||
1863 | } | ||
1864 | else | ||
1865 | /* uncompressed data */ | ||
1866 | if (efn->compression == 0 | ||
1867 | && efn->ciphered == 0) | ||
1868 | data = efn->data ? efn->data : ef->data + efn->offset; /* compressed data */ | ||
1869 | else | ||
1870 | data = NULL; | ||
1871 | |||
1872 | /* fill in return values */ | ||
1873 | if (size_ret) | ||
1874 | *size_ret = size; | ||
1875 | |||
1876 | UNLOCK_FILE(ef); | ||
1877 | |||
1878 | return data; | ||
1879 | |||
1880 | on_error: | ||
1881 | UNLOCK_FILE(ef); | ||
1882 | return NULL; | ||
1883 | } | ||
1884 | |||
1885 | EAPI const char * | ||
1886 | eet_alias_get(Eet_File *ef, | ||
1887 | const char *name) | ||
1888 | { | ||
1889 | Eet_File_Node *efn; | ||
1890 | const char *data = NULL; | ||
1891 | int size = 0; | ||
1892 | |||
1893 | /* check to see its' an eet file pointer */ | ||
1894 | if (eet_check_pointer(ef)) | ||
1895 | return NULL; | ||
1896 | |||
1897 | if (!name) | ||
1898 | return NULL; | ||
1899 | |||
1900 | if ((ef->mode != EET_FILE_MODE_READ) && | ||
1901 | (ef->mode != EET_FILE_MODE_READ_WRITE)) | ||
1902 | return NULL; | ||
1903 | |||
1904 | /* no header, return NULL */ | ||
1905 | if (eet_check_header(ef)) | ||
1906 | return NULL; | ||
1907 | |||
1908 | LOCK_FILE(ef); | ||
1909 | |||
1910 | /* hunt hash bucket */ | ||
1911 | efn = find_node_by_name(ef, name); | ||
1912 | if (!efn) | ||
1913 | goto on_error; | ||
1914 | |||
1915 | /* trick to detect data in memory instead of mmaped from disk */ | ||
1916 | if (efn->offset > ef->data_size && !efn->data) | ||
1917 | goto on_error; | ||
1918 | |||
1919 | /* get size (uncompressed, if compressed at all) */ | ||
1920 | size = efn->data_size; | ||
1921 | |||
1922 | if (!efn->alias) return NULL; | ||
1923 | data = efn->data ? efn->data : ef->data + efn->offset; | ||
1924 | |||
1925 | /* handle alias case */ | ||
1926 | if (efn->compression) | ||
1927 | { | ||
1928 | char *tmp; | ||
1929 | int compr_size = efn->size; | ||
1930 | uLongf dlen; | ||
1931 | |||
1932 | tmp = alloca(sizeof (compr_size)); | ||
1933 | dlen = size; | ||
1934 | |||
1935 | if (uncompress((Bytef *)tmp, &dlen, (Bytef *)data, | ||
1936 | (uLongf)compr_size)) | ||
1937 | goto on_error; | ||
1938 | |||
1939 | if (tmp[compr_size - 1] != '\0') | ||
1940 | goto on_error; | ||
1941 | |||
1942 | UNLOCK_FILE(ef); | ||
1943 | |||
1944 | return eina_stringshare_add(tmp); | ||
1945 | } | ||
1946 | |||
1947 | if (!data) | ||
1948 | goto on_error; | ||
1949 | |||
1950 | if (data[size - 1] != '\0') | ||
1951 | goto on_error; | ||
1952 | |||
1953 | UNLOCK_FILE(ef); | ||
1954 | |||
1955 | return eina_stringshare_add(data); | ||
1956 | |||
1957 | on_error: | ||
1958 | UNLOCK_FILE(ef); | ||
1959 | return NULL; | ||
1960 | } | ||
1961 | |||
1962 | EAPI Eina_Bool | ||
1963 | eet_alias(Eet_File *ef, | ||
1964 | const char *name, | ||
1965 | const char *destination, | ||
1966 | int comp) | ||
1967 | { | ||
1968 | Eet_File_Node *efn; | ||
1969 | void *data2; | ||
1970 | Eina_Bool exists_already = EINA_FALSE; | ||
1971 | int data_size; | ||
1972 | int hash; | ||
1973 | |||
1974 | /* check to see its' an eet file pointer */ | ||
1975 | if (eet_check_pointer(ef)) | ||
1976 | return EINA_FALSE; | ||
1977 | |||
1978 | if ((!name) || (!destination)) | ||
1979 | return EINA_FALSE; | ||
1980 | |||
1981 | if ((ef->mode != EET_FILE_MODE_WRITE) && | ||
1982 | (ef->mode != EET_FILE_MODE_READ_WRITE)) | ||
1983 | return EINA_FALSE; | ||
1984 | |||
1985 | LOCK_FILE(ef); | ||
1986 | |||
1987 | if (!ef->header) | ||
1988 | { | ||
1989 | /* allocate header */ | ||
1990 | ef->header = eet_file_header_calloc(1); | ||
1991 | if (!ef->header) | ||
1992 | goto on_error; | ||
1993 | |||
1994 | ef->header->magic = EET_MAGIC_FILE_HEADER; | ||
1995 | /* allocate directory block in ram */ | ||
1996 | ef->header->directory = eet_file_directory_calloc(1); | ||
1997 | if (!ef->header->directory) | ||
1998 | { | ||
1999 | eet_file_header_mp_free(ef->header); | ||
2000 | ef->header = NULL; | ||
2001 | goto on_error; | ||
2002 | } | ||
2003 | |||
2004 | /* 8 bit hash table (256 buckets) */ | ||
2005 | ef->header->directory->size = 8; | ||
2006 | /* allocate base hash table */ | ||
2007 | ef->header->directory->nodes = | ||
2008 | calloc(1, sizeof(Eet_File_Node *) * | ||
2009 | (1 << ef->header->directory->size)); | ||
2010 | if (!ef->header->directory->nodes) | ||
2011 | { | ||
2012 | eet_file_directory_mp_free(ef->header->directory); | ||
2013 | ef->header = NULL; | ||
2014 | goto on_error; | ||
2015 | } | ||
2016 | } | ||
2017 | |||
2018 | /* figure hash bucket */ | ||
2019 | hash = _eet_hash_gen(name, ef->header->directory->size); | ||
2020 | |||
2021 | data_size = comp ? | ||
2022 | 12 + (((strlen(destination) + 1) * 101) / 100) | ||
2023 | : strlen(destination) + 1; | ||
2024 | |||
2025 | data2 = malloc(data_size); | ||
2026 | if (!data2) | ||
2027 | goto on_error; | ||
2028 | |||
2029 | /* if we want to compress */ | ||
2030 | if (comp) | ||
2031 | { | ||
2032 | uLongf buflen; | ||
2033 | |||
2034 | /* compress the data with max compression */ | ||
2035 | buflen = (uLongf)data_size; | ||
2036 | if (compress2((Bytef *)data2, &buflen, (Bytef *)destination, | ||
2037 | (uLong)strlen(destination) + 1, | ||
2038 | Z_BEST_COMPRESSION) != Z_OK) | ||
2039 | { | ||
2040 | free(data2); | ||
2041 | goto on_error; | ||
2042 | } | ||
2043 | |||
2044 | /* record compressed chunk size */ | ||
2045 | data_size = (int)buflen; | ||
2046 | if (data_size < 0 || data_size >= (int)(strlen(destination) + 1)) | ||
2047 | { | ||
2048 | comp = 0; | ||
2049 | data_size = strlen(destination) + 1; | ||
2050 | } | ||
2051 | else | ||
2052 | { | ||
2053 | void *data3; | ||
2054 | |||
2055 | data3 = realloc(data2, data_size); | ||
2056 | if (data3) | ||
2057 | data2 = data3; | ||
2058 | } | ||
2059 | } | ||
2060 | |||
2061 | if (!comp) | ||
2062 | memcpy(data2, destination, data_size); | ||
2063 | |||
2064 | /* Does this node already exist? */ | ||
2065 | for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next) | ||
2066 | { | ||
2067 | /* if it matches */ | ||
2068 | if ((efn->name) && (eet_string_match(efn->name, name))) | ||
2069 | { | ||
2070 | free(efn->data); | ||
2071 | efn->alias = 1; | ||
2072 | efn->ciphered = 0; | ||
2073 | efn->compression = !!comp; | ||
2074 | efn->size = data_size; | ||
2075 | efn->data_size = strlen(destination) + 1; | ||
2076 | efn->data = data2; | ||
2077 | /* Put the offset above the limit to avoid direct access */ | ||
2078 | efn->offset = ef->data_size + 1; | ||
2079 | exists_already = EINA_TRUE; | ||
2080 | |||
2081 | break; | ||
2082 | } | ||
2083 | } | ||
2084 | if (!exists_already) | ||
2085 | { | ||
2086 | efn = eet_file_node_malloc(1); | ||
2087 | if (!efn) | ||
2088 | { | ||
2089 | free(data2); | ||
2090 | goto on_error; | ||
2091 | } | ||
2092 | |||
2093 | efn->name = strdup(name); | ||
2094 | efn->name_size = strlen(efn->name) + 1; | ||
2095 | efn->free_name = 1; | ||
2096 | |||
2097 | efn->next = ef->header->directory->nodes[hash]; | ||
2098 | ef->header->directory->nodes[hash] = efn; | ||
2099 | /* Put the offset above the limit to avoid direct access */ | ||
2100 | efn->offset = ef->data_size + 1; | ||
2101 | efn->alias = 1; | ||
2102 | efn->ciphered = 0; | ||
2103 | efn->compression = !!comp; | ||
2104 | efn->size = data_size; | ||
2105 | efn->data_size = strlen(destination) + 1; | ||
2106 | efn->data = data2; | ||
2107 | } | ||
2108 | |||
2109 | /* flags that writes are pending */ | ||
2110 | ef->writes_pending = 1; | ||
2111 | |||
2112 | UNLOCK_FILE(ef); | ||
2113 | return EINA_TRUE; | ||
2114 | |||
2115 | on_error: | ||
2116 | UNLOCK_FILE(ef); | ||
2117 | return EINA_FALSE; | ||
2118 | } | ||
2119 | |||
2120 | EAPI int | ||
2121 | eet_write_cipher(Eet_File *ef, | ||
2122 | const char *name, | ||
2123 | const void *data, | ||
2124 | int size, | ||
2125 | int comp, | ||
2126 | const char *cipher_key) | ||
2127 | { | ||
2128 | Eet_File_Node *efn; | ||
2129 | void *data2 = NULL; | ||
2130 | int exists_already = 0; | ||
2131 | int data_size; | ||
2132 | int hash; | ||
2133 | |||
2134 | /* check to see its' an eet file pointer */ | ||
2135 | if (eet_check_pointer(ef)) | ||
2136 | return 0; | ||
2137 | |||
2138 | if ((!name) || (!data) || (size <= 0)) | ||
2139 | return 0; | ||
2140 | |||
2141 | if ((ef->mode != EET_FILE_MODE_WRITE) && | ||
2142 | (ef->mode != EET_FILE_MODE_READ_WRITE)) | ||
2143 | return 0; | ||
2144 | |||
2145 | LOCK_FILE(ef); | ||
2146 | |||
2147 | if (!ef->header) | ||
2148 | { | ||
2149 | /* allocate header */ | ||
2150 | ef->header = eet_file_header_calloc(1); | ||
2151 | if (!ef->header) | ||
2152 | goto on_error; | ||
2153 | |||
2154 | ef->header->magic = EET_MAGIC_FILE_HEADER; | ||
2155 | /* allocate directory block in ram */ | ||
2156 | ef->header->directory = eet_file_directory_calloc(1); | ||
2157 | if (!ef->header->directory) | ||
2158 | { | ||
2159 | eet_file_header_mp_free(ef->header); | ||
2160 | ef->header = NULL; | ||
2161 | goto on_error; | ||
2162 | } | ||
2163 | |||
2164 | /* 8 bit hash table (256 buckets) */ | ||
2165 | ef->header->directory->size = 8; | ||
2166 | /* allocate base hash table */ | ||
2167 | ef->header->directory->nodes = | ||
2168 | calloc(1, sizeof(Eet_File_Node *) * | ||
2169 | (1 << ef->header->directory->size)); | ||
2170 | if (!ef->header->directory->nodes) | ||
2171 | { | ||
2172 | eet_file_directory_mp_free(ef->header->directory); | ||
2173 | ef->header = NULL; | ||
2174 | goto on_error; | ||
2175 | } | ||
2176 | } | ||
2177 | |||
2178 | /* figure hash bucket */ | ||
2179 | hash = _eet_hash_gen(name, ef->header->directory->size); | ||
2180 | |||
2181 | data_size = comp ? 12 + ((size * 101) / 100) : size; | ||
2182 | |||
2183 | if (comp || !cipher_key) | ||
2184 | { | ||
2185 | data2 = malloc(data_size); | ||
2186 | if (!data2) | ||
2187 | goto on_error; | ||
2188 | } | ||
2189 | |||
2190 | /* if we want to compress */ | ||
2191 | if (comp) | ||
2192 | { | ||
2193 | uLongf buflen; | ||
2194 | |||
2195 | /* compress the data with max compression */ | ||
2196 | buflen = (uLongf)data_size; | ||
2197 | if (compress2((Bytef *)data2, &buflen, (Bytef *)data, | ||
2198 | (uLong)size, Z_BEST_COMPRESSION) != Z_OK) | ||
2199 | { | ||
2200 | free(data2); | ||
2201 | goto on_error; | ||
2202 | } | ||
2203 | |||
2204 | /* record compressed chunk size */ | ||
2205 | data_size = (int)buflen; | ||
2206 | if (data_size < 0 || data_size >= size) | ||
2207 | { | ||
2208 | comp = 0; | ||
2209 | data_size = size; | ||
2210 | } | ||
2211 | else | ||
2212 | { | ||
2213 | void *data3; | ||
2214 | |||
2215 | data3 = realloc(data2, data_size); | ||
2216 | if (data3) | ||
2217 | data2 = data3; | ||
2218 | } | ||
2219 | } | ||
2220 | |||
2221 | if (cipher_key) | ||
2222 | { | ||
2223 | void *data_ciphered = NULL; | ||
2224 | unsigned int data_ciphered_sz = 0; | ||
2225 | const void *tmp; | ||
2226 | |||
2227 | tmp = comp ? data2 : data; | ||
2228 | if (!eet_cipher(tmp, data_size, cipher_key, strlen(cipher_key), | ||
2229 | &data_ciphered, &data_ciphered_sz)) | ||
2230 | { | ||
2231 | if (data2) | ||
2232 | free(data2); | ||
2233 | |||
2234 | data2 = data_ciphered; | ||
2235 | data_size = data_ciphered_sz; | ||
2236 | } | ||
2237 | else | ||
2238 | { | ||
2239 | if (data_ciphered) | ||
2240 | free(data_ciphered); | ||
2241 | |||
2242 | cipher_key = NULL; | ||
2243 | } | ||
2244 | } | ||
2245 | else | ||
2246 | if (!comp) | ||
2247 | memcpy(data2, data, size); | ||
2248 | |||
2249 | /* Does this node already exist? */ | ||
2250 | for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next) | ||
2251 | { | ||
2252 | /* if it matches */ | ||
2253 | if ((efn->name) && (eet_string_match(efn->name, name))) | ||
2254 | { | ||
2255 | free(efn->data); | ||
2256 | efn->alias = 0; | ||
2257 | efn->ciphered = cipher_key ? 1 : 0; | ||
2258 | efn->compression = !!comp; | ||
2259 | efn->size = data_size; | ||
2260 | efn->data_size = size; | ||
2261 | efn->data = data2; | ||
2262 | /* Put the offset above the limit to avoid direct access */ | ||
2263 | efn->offset = ef->data_size + 1; | ||
2264 | exists_already = 1; | ||
2265 | break; | ||
2266 | } | ||
2267 | } | ||
2268 | if (!exists_already) | ||
2269 | { | ||
2270 | efn = eet_file_node_malloc(1); | ||
2271 | if (!efn) | ||
2272 | { | ||
2273 | free(data2); | ||
2274 | goto on_error; | ||
2275 | } | ||
2276 | |||
2277 | efn->name = strdup(name); | ||
2278 | efn->name_size = strlen(efn->name) + 1; | ||
2279 | efn->free_name = 1; | ||
2280 | |||
2281 | efn->next = ef->header->directory->nodes[hash]; | ||
2282 | ef->header->directory->nodes[hash] = efn; | ||
2283 | /* Put the offset above the limit to avoid direct access */ | ||
2284 | efn->offset = ef->data_size + 1; | ||
2285 | efn->alias = 0; | ||
2286 | efn->ciphered = cipher_key ? 1 : 0; | ||
2287 | efn->compression = !!comp; | ||
2288 | efn->size = data_size; | ||
2289 | efn->data_size = size; | ||
2290 | efn->data = data2; | ||
2291 | } | ||
2292 | |||
2293 | /* flags that writes are pending */ | ||
2294 | ef->writes_pending = 1; | ||
2295 | UNLOCK_FILE(ef); | ||
2296 | return data_size; | ||
2297 | |||
2298 | on_error: | ||
2299 | UNLOCK_FILE(ef); | ||
2300 | return 0; | ||
2301 | } | ||
2302 | |||
2303 | EAPI int | ||
2304 | eet_write(Eet_File *ef, | ||
2305 | const char *name, | ||
2306 | const void *data, | ||
2307 | int size, | ||
2308 | int comp) | ||
2309 | { | ||
2310 | return eet_write_cipher(ef, name, data, size, comp, NULL); | ||
2311 | } | ||
2312 | |||
2313 | EAPI int | ||
2314 | eet_delete(Eet_File *ef, | ||
2315 | const char *name) | ||
2316 | { | ||
2317 | Eet_File_Node *efn; | ||
2318 | Eet_File_Node *pefn; | ||
2319 | int hash; | ||
2320 | int exists_already = 0; | ||
2321 | |||
2322 | /* check to see its' an eet file pointer */ | ||
2323 | if (eet_check_pointer(ef)) | ||
2324 | return 0; | ||
2325 | |||
2326 | if (!name) | ||
2327 | return 0; | ||
2328 | |||
2329 | /* deleting keys is only possible in RW or WRITE mode */ | ||
2330 | if (ef->mode == EET_FILE_MODE_READ) | ||
2331 | return 0; | ||
2332 | |||
2333 | if (eet_check_header(ef)) | ||
2334 | return 0; | ||
2335 | |||
2336 | LOCK_FILE(ef); | ||
2337 | |||
2338 | /* figure hash bucket */ | ||
2339 | hash = _eet_hash_gen(name, ef->header->directory->size); | ||
2340 | |||
2341 | /* Does this node already exist? */ | ||
2342 | for (pefn = NULL, efn = ef->header->directory->nodes[hash]; | ||
2343 | efn; | ||
2344 | pefn = efn, efn = efn->next) | ||
2345 | { | ||
2346 | /* if it matches */ | ||
2347 | if (eet_string_match(efn->name, name)) | ||
2348 | { | ||
2349 | if (efn->data) | ||
2350 | free(efn->data); | ||
2351 | |||
2352 | if (!pefn) | ||
2353 | ef->header->directory->nodes[hash] = efn->next; | ||
2354 | else | ||
2355 | pefn->next = efn->next; | ||
2356 | |||
2357 | if (efn->free_name) | ||
2358 | free(efn->name); | ||
2359 | |||
2360 | eet_file_node_mp_free(efn); | ||
2361 | exists_already = 1; | ||
2362 | break; | ||
2363 | } | ||
2364 | } | ||
2365 | /* flags that writes are pending */ | ||
2366 | if (exists_already) | ||
2367 | ef->writes_pending = 1; | ||
2368 | |||
2369 | UNLOCK_FILE(ef); | ||
2370 | |||
2371 | /* update access time */ | ||
2372 | return exists_already; | ||
2373 | } | ||
2374 | |||
2375 | EAPI Eet_Dictionary * | ||
2376 | eet_dictionary_get(Eet_File *ef) | ||
2377 | { | ||
2378 | if (eet_check_pointer(ef)) | ||
2379 | return NULL; | ||
2380 | |||
2381 | return ef->ed; | ||
2382 | } | ||
2383 | |||
2384 | EAPI char ** | ||
2385 | eet_list(Eet_File *ef, | ||
2386 | const char *glob, | ||
2387 | int *count_ret) | ||
2388 | { | ||
2389 | Eet_File_Node *efn; | ||
2390 | char **list_ret = NULL; | ||
2391 | int list_count = 0; | ||
2392 | int list_count_alloc = 0; | ||
2393 | int i, num; | ||
2394 | |||
2395 | /* check to see its' an eet file pointer */ | ||
2396 | if (eet_check_pointer(ef) || eet_check_header(ef) || | ||
2397 | (!glob) || | ||
2398 | ((ef->mode != EET_FILE_MODE_READ) && | ||
2399 | (ef->mode != EET_FILE_MODE_READ_WRITE))) | ||
2400 | { | ||
2401 | if (count_ret) | ||
2402 | *count_ret = 0; | ||
2403 | |||
2404 | return NULL; | ||
2405 | } | ||
2406 | |||
2407 | if (!strcmp(glob, "*")) | ||
2408 | glob = NULL; | ||
2409 | |||
2410 | LOCK_FILE(ef); | ||
2411 | |||
2412 | /* loop through all entries */ | ||
2413 | num = (1 << ef->header->directory->size); | ||
2414 | for (i = 0; i < num; i++) | ||
2415 | { | ||
2416 | for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) | ||
2417 | { | ||
2418 | /* if the entry matches the input glob | ||
2419 | * check for * explicitly, because on some systems, * isn't well | ||
2420 | * supported | ||
2421 | */ | ||
2422 | if ((!glob) || !fnmatch(glob, efn->name, 0)) | ||
2423 | { | ||
2424 | /* add it to our list */ | ||
2425 | list_count++; | ||
2426 | |||
2427 | /* only realloc in 32 entry chunks */ | ||
2428 | if (list_count > list_count_alloc) | ||
2429 | { | ||
2430 | char **new_list = NULL; | ||
2431 | |||
2432 | list_count_alloc += 64; | ||
2433 | new_list = | ||
2434 | realloc(list_ret, list_count_alloc * (sizeof(char *))); | ||
2435 | if (!new_list) | ||
2436 | { | ||
2437 | free(list_ret); | ||
2438 | |||
2439 | goto on_error; | ||
2440 | } | ||
2441 | |||
2442 | list_ret = new_list; | ||
2443 | } | ||
2444 | |||
2445 | /* put pointer of name string in */ | ||
2446 | list_ret[list_count - 1] = efn->name; | ||
2447 | } | ||
2448 | } | ||
2449 | } | ||
2450 | |||
2451 | UNLOCK_FILE(ef); | ||
2452 | |||
2453 | /* return count and list */ | ||
2454 | if (count_ret) | ||
2455 | *count_ret = list_count; | ||
2456 | |||
2457 | return list_ret; | ||
2458 | |||
2459 | on_error: | ||
2460 | UNLOCK_FILE(ef); | ||
2461 | |||
2462 | if (count_ret) | ||
2463 | *count_ret = 0; | ||
2464 | |||
2465 | return NULL; | ||
2466 | } | ||
2467 | |||
2468 | EAPI int | ||
2469 | eet_num_entries(Eet_File *ef) | ||
2470 | { | ||
2471 | int i, num, ret = 0; | ||
2472 | Eet_File_Node *efn; | ||
2473 | |||
2474 | /* check to see its' an eet file pointer */ | ||
2475 | if (eet_check_pointer(ef) || eet_check_header(ef) || | ||
2476 | ((ef->mode != EET_FILE_MODE_READ) && | ||
2477 | (ef->mode != EET_FILE_MODE_READ_WRITE))) | ||
2478 | return -1; | ||
2479 | |||
2480 | LOCK_FILE(ef); | ||
2481 | |||
2482 | /* loop through all entries */ | ||
2483 | num = (1 << ef->header->directory->size); | ||
2484 | for (i = 0; i < num; i++) | ||
2485 | { | ||
2486 | for (efn = ef->header->directory->nodes[i]; efn; efn = efn->next) | ||
2487 | ret++; | ||
2488 | } | ||
2489 | |||
2490 | UNLOCK_FILE(ef); | ||
2491 | |||
2492 | return ret; | ||
2493 | } | ||
2494 | |||
2495 | static Eet_File_Node * | ||
2496 | find_node_by_name(Eet_File *ef, | ||
2497 | const char *name) | ||
2498 | { | ||
2499 | Eet_File_Node *efn; | ||
2500 | int hash; | ||
2501 | |||
2502 | /* get hash bucket this should be in */ | ||
2503 | hash = _eet_hash_gen(name, ef->header->directory->size); | ||
2504 | |||
2505 | for (efn = ef->header->directory->nodes[hash]; efn; efn = efn->next) | ||
2506 | { | ||
2507 | if (eet_string_match(efn->name, name)) | ||
2508 | return efn; | ||
2509 | } | ||
2510 | |||
2511 | return NULL; | ||
2512 | } | ||
2513 | |||
2514 | static int | ||
2515 | read_data_from_disk(Eet_File *ef, | ||
2516 | Eet_File_Node *efn, | ||
2517 | void *buf, | ||
2518 | int len) | ||
2519 | { | ||
2520 | if (efn->offset > ef->data_size) | ||
2521 | return 0; | ||
2522 | |||
2523 | if (!ef->data) | ||
2524 | return 0; | ||
2525 | |||
2526 | if ((efn->offset + len) > ef->data_size) | ||
2527 | return 0; | ||
2528 | |||
2529 | memcpy(buf, ef->data + efn->offset, len); | ||
2530 | |||
2531 | return len; | ||
2532 | } | ||
2533 | |||