diff options
author | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
---|---|---|
committer | David Walter Seikel | 2012-01-04 18:41:13 +1000 |
commit | dd7595a3475407a7fa96a97393bae8c5220e8762 (patch) | |
tree | e341e911d7eb911a51684a7412ef7f7c7605d28e /libraries/eina/src/lib/eina_file_win32.c | |
parent | Add the skeleton. (diff) | |
download | SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.zip SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.gz SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.bz2 SledjHamr-dd7595a3475407a7fa96a97393bae8c5220e8762.tar.xz |
Add the base Enlightenment Foundation Libraries - eina, eet, evas, ecore, embryo, and edje.
Note that embryo wont be used, but I'm not sure yet if you can build edje without it.
Diffstat (limited to 'libraries/eina/src/lib/eina_file_win32.c')
-rw-r--r-- | libraries/eina/src/lib/eina_file_win32.c | 1021 |
1 files changed, 1021 insertions, 0 deletions
diff --git a/libraries/eina/src/lib/eina_file_win32.c b/libraries/eina/src/lib/eina_file_win32.c new file mode 100644 index 0000000..1cd8665 --- /dev/null +++ b/libraries/eina/src/lib/eina_file_win32.c | |||
@@ -0,0 +1,1021 @@ | |||
1 | /* EINA - EFL data type library | ||
2 | * Copyright (C) 2010 Vincent Torri | ||
3 | * | ||
4 | * This library is free software; you can redistribute it and/or | ||
5 | * modify it under the terms of the GNU Lesser General Public | ||
6 | * License as published by the Free Software Foundation; either | ||
7 | * version 2.1 of the License, or (at your option) any later version. | ||
8 | * | ||
9 | * This library is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
12 | * Lesser General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU Lesser General Public | ||
15 | * License along with this library; | ||
16 | * if not, see <http://www.gnu.org/licenses/>. | ||
17 | */ | ||
18 | |||
19 | #ifdef HAVE_CONFIG_H | ||
20 | # include "config.h" | ||
21 | #endif | ||
22 | |||
23 | #ifdef HAVE_ALLOCA_H | ||
24 | # include <alloca.h> | ||
25 | #elif defined __GNUC__ | ||
26 | # define alloca __builtin_alloca | ||
27 | #elif defined _AIX | ||
28 | # define alloca __alloca | ||
29 | #elif defined _MSC_VER | ||
30 | # include <malloc.h> | ||
31 | # define alloca _alloca | ||
32 | #else | ||
33 | # include <stddef.h> | ||
34 | # ifdef __cplusplus | ||
35 | extern "C" | ||
36 | # endif | ||
37 | void *alloca (size_t); | ||
38 | #endif | ||
39 | |||
40 | #define WIN32_LEAN_AND_MEAN | ||
41 | #include <windows.h> | ||
42 | #undef WIN32_LEAN_AND_MEAN | ||
43 | |||
44 | //#include <Evil.h> | ||
45 | |||
46 | #include "eina_config.h" | ||
47 | #include "eina_private.h" | ||
48 | |||
49 | /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ | ||
50 | #include "eina_safety_checks.h" | ||
51 | #include "eina_file.h" | ||
52 | #include "eina_stringshare.h" | ||
53 | #include "eina_hash.h" | ||
54 | #include "eina_list.h" | ||
55 | |||
56 | /*============================================================================* | ||
57 | * Local * | ||
58 | *============================================================================*/ | ||
59 | |||
60 | /** | ||
61 | * @cond LOCAL | ||
62 | */ | ||
63 | |||
64 | #ifndef EINA_LOG_COLOR_DEFAULT | ||
65 | #define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN | ||
66 | #endif | ||
67 | |||
68 | #ifdef ERR | ||
69 | #undef ERR | ||
70 | #endif | ||
71 | #define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__) | ||
72 | |||
73 | #ifdef WRN | ||
74 | #undef WRN | ||
75 | #endif | ||
76 | #define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__) | ||
77 | |||
78 | #ifdef DBG | ||
79 | #undef DBG | ||
80 | #endif | ||
81 | #define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__) | ||
82 | |||
83 | #ifdef MAP_FAILED | ||
84 | # undef MAP_FAILED | ||
85 | #endif | ||
86 | #define MAP_FAILED ((void *)-1) | ||
87 | |||
88 | typedef struct _Eina_File_Iterator Eina_File_Iterator; | ||
89 | typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator; | ||
90 | typedef struct _Eina_File_Map Eina_File_Map; | ||
91 | |||
92 | struct _Eina_File_Iterator | ||
93 | { | ||
94 | Eina_Iterator iterator; | ||
95 | |||
96 | WIN32_FIND_DATA data; | ||
97 | HANDLE handle; | ||
98 | size_t length; | ||
99 | Eina_Bool is_last : 1; | ||
100 | |||
101 | char dir[1]; | ||
102 | }; | ||
103 | |||
104 | struct _Eina_File_Direct_Iterator | ||
105 | { | ||
106 | Eina_Iterator iterator; | ||
107 | |||
108 | WIN32_FIND_DATA data; | ||
109 | HANDLE handle; | ||
110 | size_t length; | ||
111 | Eina_Bool is_last : 1; | ||
112 | |||
113 | Eina_File_Direct_Info info; | ||
114 | |||
115 | char dir[1]; | ||
116 | }; | ||
117 | |||
118 | struct _Eina_File | ||
119 | { | ||
120 | const char *filename; | ||
121 | |||
122 | Eina_Hash *map; | ||
123 | Eina_Hash *rmap; | ||
124 | void *global_map; | ||
125 | |||
126 | ULONGLONG length; | ||
127 | ULONGLONG mtime; | ||
128 | |||
129 | int refcount; | ||
130 | int global_refcount; | ||
131 | |||
132 | HANDLE handle; | ||
133 | HANDLE fm; | ||
134 | |||
135 | Eina_Bool shared : 1; | ||
136 | Eina_Bool delete_me : 1; | ||
137 | }; | ||
138 | |||
139 | struct _Eina_File_Map | ||
140 | { | ||
141 | void *map; | ||
142 | |||
143 | unsigned long int offset; | ||
144 | unsigned long int length; | ||
145 | |||
146 | int refcount; | ||
147 | }; | ||
148 | |||
149 | static Eina_Hash *_eina_file_cache = NULL; | ||
150 | static Eina_List *_eina_file_cache_lru = NULL; | ||
151 | static Eina_List *_eina_file_cache_delete = NULL; | ||
152 | |||
153 | static int _eina_file_log_dom = -1; | ||
154 | |||
155 | static void | ||
156 | _eina_file_win32_backslash_change(char *dir) | ||
157 | { | ||
158 | char *tmp; | ||
159 | |||
160 | tmp = dir; | ||
161 | while (*tmp) | ||
162 | { | ||
163 | if (*tmp == '/') *tmp = '\\'; | ||
164 | tmp++; | ||
165 | } | ||
166 | } | ||
167 | |||
168 | static Eina_Bool | ||
169 | _eina_file_win32_is_dir(const char *dir) | ||
170 | { | ||
171 | #ifdef UNICODE | ||
172 | wchar_t *wdir = NULL; | ||
173 | #endif | ||
174 | DWORD attr; | ||
175 | |||
176 | /* check if it's a directory */ | ||
177 | #ifdef UNICODE | ||
178 | wdir = evil_char_to_wchar(dir); | ||
179 | if (!wdir) | ||
180 | return EINA_FALSE; | ||
181 | |||
182 | attr = GetFileAttributes(wdir); | ||
183 | free(wdir); | ||
184 | #else | ||
185 | attr = GetFileAttributes(dir); | ||
186 | #endif | ||
187 | |||
188 | if (attr == 0xFFFFFFFF) | ||
189 | return EINA_FALSE; | ||
190 | |||
191 | if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) | ||
192 | return EINA_FALSE; | ||
193 | |||
194 | return EINA_TRUE; | ||
195 | } | ||
196 | |||
197 | static char * | ||
198 | _eina_file_win32_dir_new(const char *dir) | ||
199 | { | ||
200 | char *new_dir; | ||
201 | size_t length; | ||
202 | |||
203 | length = strlen(dir); | ||
204 | |||
205 | new_dir = (char *)malloc(sizeof(char) * length + 5); | ||
206 | if (!new_dir) | ||
207 | return NULL; | ||
208 | |||
209 | memcpy(new_dir, dir, length); | ||
210 | memcpy(new_dir + length, "\\*.*", 5); | ||
211 | _eina_file_win32_backslash_change(new_dir); | ||
212 | |||
213 | return new_dir; | ||
214 | } | ||
215 | |||
216 | static HANDLE | ||
217 | _eina_file_win32_first_file(const char *dir, WIN32_FIND_DATA *fd) | ||
218 | { | ||
219 | HANDLE h; | ||
220 | #ifdef UNICODE | ||
221 | wchar_t *wdir = NULL; | ||
222 | |||
223 | wdir = evil_char_to_wchar(dir); | ||
224 | if (!wdir) | ||
225 | return NULL; | ||
226 | |||
227 | h = FindFirstFile(wdir, fd); | ||
228 | free(wdir); | ||
229 | #else | ||
230 | h = FindFirstFile(dir, fd); | ||
231 | #endif | ||
232 | |||
233 | if (!h) | ||
234 | return NULL; | ||
235 | |||
236 | while ((fd->cFileName[0] == '.') && | ||
237 | ((fd->cFileName[1] == '\0') || | ||
238 | ((fd->cFileName[1] == '.') && (fd->cFileName[2] == '\0')))) | ||
239 | { | ||
240 | if (!FindNextFile(h, fd)) | ||
241 | return NULL; | ||
242 | } | ||
243 | |||
244 | return h; | ||
245 | } | ||
246 | |||
247 | static Eina_Bool | ||
248 | _eina_file_win32_ls_iterator_next(Eina_File_Iterator *it, void **data) | ||
249 | { | ||
250 | #ifdef UNICODE | ||
251 | wchar_t *old_name; | ||
252 | #else | ||
253 | char *old_name; | ||
254 | #endif | ||
255 | char *name; | ||
256 | char *cname; | ||
257 | size_t length; | ||
258 | Eina_Bool is_last; | ||
259 | Eina_Bool res = EINA_TRUE; | ||
260 | |||
261 | if (it->handle == INVALID_HANDLE_VALUE) | ||
262 | return EINA_FALSE; | ||
263 | |||
264 | is_last = it->is_last; | ||
265 | #ifdef UNICODE | ||
266 | old_name = _wcsdup(it->data.cFileName); | ||
267 | #else | ||
268 | old_name = _strdup(it->data.cFileName); | ||
269 | #endif | ||
270 | if (!old_name) | ||
271 | return EINA_FALSE; | ||
272 | |||
273 | do { | ||
274 | if (!FindNextFile(it->handle, &it->data)) | ||
275 | { | ||
276 | if (GetLastError() == ERROR_NO_MORE_FILES) | ||
277 | it->is_last = EINA_TRUE; | ||
278 | else | ||
279 | res = EINA_FALSE; | ||
280 | } | ||
281 | } while ((it->data.cFileName[0] == '.') && | ||
282 | ((it->data.cFileName[1] == '\0') || | ||
283 | ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */ | ||
284 | |||
285 | #ifdef UNICODE | ||
286 | cname = evil_wchar_to_char(old_name); | ||
287 | if (!cname) | ||
288 | return EINA_FALSE; | ||
289 | #else | ||
290 | cname = old_name; | ||
291 | #endif | ||
292 | |||
293 | length = strlen(cname); | ||
294 | name = alloca(length + 2 + it->length); | ||
295 | |||
296 | memcpy(name, it->dir, it->length); | ||
297 | memcpy(name + it->length, "\\", 1); | ||
298 | memcpy(name + it->length + 1, cname, length + 1); | ||
299 | |||
300 | *data = (char *)eina_stringshare_add(name); | ||
301 | |||
302 | #ifdef UNICODE | ||
303 | free(cname); | ||
304 | #endif | ||
305 | free(old_name); | ||
306 | |||
307 | if (is_last) | ||
308 | res = EINA_FALSE; | ||
309 | |||
310 | return res; | ||
311 | } | ||
312 | |||
313 | static HANDLE | ||
314 | _eina_file_win32_ls_iterator_container(Eina_File_Iterator *it) | ||
315 | { | ||
316 | return it->handle; | ||
317 | } | ||
318 | |||
319 | static void | ||
320 | _eina_file_win32_ls_iterator_free(Eina_File_Iterator *it) | ||
321 | { | ||
322 | if (it->handle != INVALID_HANDLE_VALUE) | ||
323 | FindClose(it->handle); | ||
324 | |||
325 | EINA_MAGIC_SET(&it->iterator, 0); | ||
326 | free(it); | ||
327 | } | ||
328 | |||
329 | static Eina_Bool | ||
330 | _eina_file_win32_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data) | ||
331 | { | ||
332 | #ifdef UNICODE | ||
333 | wchar_t *old_name; | ||
334 | #else | ||
335 | char *old_name; | ||
336 | #endif | ||
337 | char *cname; | ||
338 | size_t length; | ||
339 | DWORD attr; | ||
340 | Eina_Bool is_last; | ||
341 | Eina_Bool res = EINA_TRUE; | ||
342 | |||
343 | if (it->handle == INVALID_HANDLE_VALUE) | ||
344 | return EINA_FALSE; | ||
345 | |||
346 | attr = it->data.dwFileAttributes; | ||
347 | is_last = it->is_last; | ||
348 | #ifdef UNICODE | ||
349 | old_name = _wcsdup(it->data.cFileName); | ||
350 | #else | ||
351 | old_name = _strdup(it->data.cFileName); | ||
352 | #endif | ||
353 | if (!old_name) | ||
354 | return EINA_FALSE; | ||
355 | |||
356 | do { | ||
357 | if (!FindNextFile(it->handle, &it->data)) | ||
358 | { | ||
359 | if (GetLastError() == ERROR_NO_MORE_FILES) | ||
360 | it->is_last = EINA_TRUE; | ||
361 | else | ||
362 | res = EINA_FALSE; | ||
363 | } | ||
364 | |||
365 | #ifdef UNICODE | ||
366 | length = wcslen(old_name); | ||
367 | #else | ||
368 | length = strlen(old_name); | ||
369 | #endif | ||
370 | if (it->info.name_start + length + 1 >= PATH_MAX) | ||
371 | { | ||
372 | free(old_name); | ||
373 | #ifdef UNICODE | ||
374 | old_name = _wcsdup(it->data.cFileName); | ||
375 | #else | ||
376 | old_name = _strdup(it->data.cFileName); | ||
377 | #endif | ||
378 | continue; | ||
379 | } | ||
380 | |||
381 | } while ((it->data.cFileName[0] == '.') && | ||
382 | ((it->data.cFileName[1] == '\0') || | ||
383 | ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */ | ||
384 | |||
385 | #ifdef UNICODE | ||
386 | cname = evil_wchar_to_char(old_name); | ||
387 | if (!cname) | ||
388 | return EINA_FALSE; | ||
389 | #else | ||
390 | cname = old_name; | ||
391 | #endif | ||
392 | |||
393 | memcpy(it->info.path + it->info.name_start, cname, length); | ||
394 | it->info.name_length = length; | ||
395 | it->info.path_length = it->info.name_start + length; | ||
396 | it->info.path[it->info.path_length] = '\0'; | ||
397 | |||
398 | if (attr & FILE_ATTRIBUTE_DIRECTORY) | ||
399 | it->info.type = EINA_FILE_DIR; | ||
400 | else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) | ||
401 | it->info.type = EINA_FILE_LNK; | ||
402 | else if (attr & (FILE_ATTRIBUTE_ARCHIVE | | ||
403 | FILE_ATTRIBUTE_COMPRESSED | | ||
404 | FILE_ATTRIBUTE_COMPRESSED | | ||
405 | FILE_ATTRIBUTE_HIDDEN | | ||
406 | FILE_ATTRIBUTE_NORMAL | | ||
407 | FILE_ATTRIBUTE_SPARSE_FILE | | ||
408 | FILE_ATTRIBUTE_TEMPORARY)) | ||
409 | it->info.type = EINA_FILE_REG; | ||
410 | else | ||
411 | it->info.type = EINA_FILE_UNKNOWN; | ||
412 | |||
413 | *data = &it->info; | ||
414 | |||
415 | #ifdef UNICODE | ||
416 | free(cname); | ||
417 | #endif | ||
418 | |||
419 | free(old_name); | ||
420 | |||
421 | if (is_last) | ||
422 | res = EINA_FALSE; | ||
423 | |||
424 | return res; | ||
425 | } | ||
426 | |||
427 | static HANDLE | ||
428 | _eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it) | ||
429 | { | ||
430 | return it->handle; | ||
431 | } | ||
432 | |||
433 | static void | ||
434 | _eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it) | ||
435 | { | ||
436 | if (it->handle != INVALID_HANDLE_VALUE) | ||
437 | FindClose(it->handle); | ||
438 | |||
439 | EINA_MAGIC_SET(&it->iterator, 0); | ||
440 | free(it); | ||
441 | } | ||
442 | |||
443 | static void | ||
444 | _eina_file_real_close(Eina_File *file) | ||
445 | { | ||
446 | eina_hash_free(file->rmap); | ||
447 | eina_hash_free(file->map); | ||
448 | |||
449 | if (file->global_map != MAP_FAILED) | ||
450 | UnmapViewOfFile(file->global_map); | ||
451 | |||
452 | CloseHandle(file->fm); | ||
453 | CloseHandle(file->handle); | ||
454 | |||
455 | eina_stringshare_del(file->filename); | ||
456 | |||
457 | free(file); | ||
458 | } | ||
459 | |||
460 | static void | ||
461 | _eina_file_map_close(Eina_File_Map *map) | ||
462 | { | ||
463 | if (map->map != MAP_FAILED) | ||
464 | UnmapViewOfFile(map->map); | ||
465 | free(map); | ||
466 | } | ||
467 | |||
468 | static unsigned int | ||
469 | _eina_file_map_key_length(const void *key __UNUSED__) | ||
470 | { | ||
471 | return sizeof (unsigned long int) * 2; | ||
472 | } | ||
473 | |||
474 | static int | ||
475 | _eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__, | ||
476 | const unsigned long int *key2, int key2_length __UNUSED__) | ||
477 | { | ||
478 | if (key1[0] - key2[0] == 0) return key1[1] - key2[1]; | ||
479 | return key1[0] - key2[0]; | ||
480 | } | ||
481 | |||
482 | static int | ||
483 | _eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__) | ||
484 | { | ||
485 | return eina_hash_int64(&key[0], sizeof (unsigned long int)) | ||
486 | ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); | ||
487 | } | ||
488 | |||
489 | Eina_Bool | ||
490 | eina_file_init(void) | ||
491 | { | ||
492 | _eina_file_log_dom = eina_log_domain_register("eina_file", | ||
493 | EINA_LOG_COLOR_DEFAULT); | ||
494 | if (_eina_file_log_dom < 0) | ||
495 | { | ||
496 | EINA_LOG_ERR("Could not register log domain: eina_file"); | ||
497 | return EINA_FALSE; | ||
498 | } | ||
499 | |||
500 | _eina_file_cache = eina_hash_string_djb2_new(EINA_FREE_CB(_eina_file_real_close)); | ||
501 | if (!_eina_file_cache) | ||
502 | { | ||
503 | ERR("Could not create cache."); | ||
504 | eina_log_domain_unregister(_eina_file_log_dom); | ||
505 | _eina_file_log_dom = -1; | ||
506 | return EINA_FALSE; | ||
507 | } | ||
508 | |||
509 | return EINA_TRUE; | ||
510 | } | ||
511 | |||
512 | Eina_Bool | ||
513 | eina_file_shutdown(void) | ||
514 | { | ||
515 | Eina_File *f; | ||
516 | Eina_List *l; | ||
517 | |||
518 | EINA_LIST_FREE(_eina_file_cache_delete, f) | ||
519 | _eina_file_real_close(f); | ||
520 | |||
521 | EINA_LIST_FOREACH(_eina_file_cache_lru, l, f) | ||
522 | eina_hash_del(_eina_file_cache, f->filename, f); | ||
523 | |||
524 | if (eina_hash_population(_eina_file_cache) > 0) | ||
525 | { | ||
526 | Eina_Iterator *it; | ||
527 | const char *key; | ||
528 | |||
529 | it = eina_hash_iterator_key_new(_eina_file_cache); | ||
530 | EINA_ITERATOR_FOREACH(it, key) | ||
531 | ERR("File [%s] still open !", key); | ||
532 | eina_iterator_free(it); | ||
533 | } | ||
534 | |||
535 | eina_hash_free(_eina_file_cache); | ||
536 | |||
537 | eina_log_domain_unregister(_eina_file_log_dom); | ||
538 | _eina_file_log_dom = -1; | ||
539 | return EINA_TRUE; | ||
540 | } | ||
541 | |||
542 | |||
543 | /** | ||
544 | * @endcond | ||
545 | */ | ||
546 | |||
547 | /*============================================================================* | ||
548 | * Global * | ||
549 | *============================================================================*/ | ||
550 | |||
551 | /*============================================================================* | ||
552 | * API * | ||
553 | *============================================================================*/ | ||
554 | |||
555 | EAPI Eina_Bool | ||
556 | eina_file_dir_list(const char *dir, | ||
557 | Eina_Bool recursive, | ||
558 | Eina_File_Dir_List_Cb cb, | ||
559 | void *data) | ||
560 | { | ||
561 | WIN32_FIND_DATA file; | ||
562 | HANDLE h; | ||
563 | char *new_dir; | ||
564 | |||
565 | EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); | ||
566 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE); | ||
567 | EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE); | ||
568 | |||
569 | if (!_eina_file_win32_is_dir(dir)) | ||
570 | return EINA_FALSE; | ||
571 | |||
572 | new_dir = _eina_file_win32_dir_new(dir); | ||
573 | if (!new_dir) | ||
574 | return EINA_FALSE; | ||
575 | |||
576 | h = _eina_file_win32_first_file(new_dir, &file); | ||
577 | |||
578 | if (h == INVALID_HANDLE_VALUE) | ||
579 | return EINA_FALSE; | ||
580 | |||
581 | do | ||
582 | { | ||
583 | char *filename; | ||
584 | |||
585 | # ifdef UNICODE | ||
586 | filename = evil_wchar_to_char(file.cFileName); | ||
587 | # else | ||
588 | filename = file.cFileName; | ||
589 | # endif /* ! UNICODE */ | ||
590 | if (!strcmp(filename, ".") || !strcmp(filename, "..")) | ||
591 | continue; | ||
592 | |||
593 | cb(filename, dir, data); | ||
594 | |||
595 | if (recursive == EINA_TRUE) | ||
596 | { | ||
597 | char *path; | ||
598 | |||
599 | path = alloca(strlen(dir) + strlen(filename) + 2); | ||
600 | strcpy(path, dir); | ||
601 | strcat(path, "/"); | ||
602 | strcat(path, filename); | ||
603 | |||
604 | if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) | ||
605 | continue; | ||
606 | |||
607 | eina_file_dir_list(path, recursive, cb, data); | ||
608 | } | ||
609 | |||
610 | # ifdef UNICODE | ||
611 | free(filename); | ||
612 | # endif /* UNICODE */ | ||
613 | |||
614 | } while (FindNextFile(h, &file)); | ||
615 | FindClose(h); | ||
616 | |||
617 | return EINA_TRUE; | ||
618 | } | ||
619 | |||
620 | EAPI Eina_Array * | ||
621 | eina_file_split(char *path) | ||
622 | { | ||
623 | Eina_Array *ea; | ||
624 | char *current; | ||
625 | size_t length; | ||
626 | |||
627 | EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); | ||
628 | |||
629 | ea = eina_array_new(16); | ||
630 | |||
631 | if (!ea) | ||
632 | return NULL; | ||
633 | |||
634 | for (current = strchr(path, '\\'); | ||
635 | current; | ||
636 | path = current + 1, current = strchr(path, '\\')) | ||
637 | { | ||
638 | length = current - path; | ||
639 | |||
640 | if (length <= 0) | ||
641 | continue; | ||
642 | |||
643 | eina_array_push(ea, path); | ||
644 | *current = '\0'; | ||
645 | } | ||
646 | |||
647 | if (*path != '\0') | ||
648 | eina_array_push(ea, path); | ||
649 | |||
650 | return ea; | ||
651 | } | ||
652 | |||
653 | EAPI Eina_Iterator * | ||
654 | eina_file_ls(const char *dir) | ||
655 | { | ||
656 | Eina_File_Iterator *it; | ||
657 | char *new_dir; | ||
658 | size_t length; | ||
659 | |||
660 | if (!dir || !*dir) | ||
661 | return NULL; | ||
662 | |||
663 | if (!_eina_file_win32_is_dir(dir)) | ||
664 | return NULL; | ||
665 | |||
666 | length = strlen(dir); | ||
667 | |||
668 | it = calloc(1, sizeof (Eina_File_Iterator) + length); | ||
669 | if (!it) | ||
670 | return NULL; | ||
671 | |||
672 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
673 | |||
674 | new_dir = _eina_file_win32_dir_new(dir); | ||
675 | if (!new_dir) | ||
676 | goto free_it; | ||
677 | |||
678 | it->handle = _eina_file_win32_first_file(new_dir, &it->data); | ||
679 | free(new_dir); | ||
680 | if (it->handle == INVALID_HANDLE_VALUE) | ||
681 | goto free_it; | ||
682 | |||
683 | memcpy(it->dir, dir, length + 1); | ||
684 | if (dir[length - 1] != '\\') | ||
685 | it->length = length; | ||
686 | else | ||
687 | it->length = length - 1; | ||
688 | _eina_file_win32_backslash_change(it->dir); | ||
689 | |||
690 | it->iterator.version = EINA_ITERATOR_VERSION; | ||
691 | it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_ls_iterator_next); | ||
692 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_ls_iterator_container); | ||
693 | it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_ls_iterator_free); | ||
694 | |||
695 | return &it->iterator; | ||
696 | |||
697 | free_it: | ||
698 | free(it); | ||
699 | |||
700 | return NULL; | ||
701 | } | ||
702 | |||
703 | EAPI Eina_Iterator * | ||
704 | eina_file_direct_ls(const char *dir) | ||
705 | { | ||
706 | Eina_File_Direct_Iterator *it; | ||
707 | char *new_dir; | ||
708 | size_t length; | ||
709 | |||
710 | if (!dir || !*dir) | ||
711 | return NULL; | ||
712 | |||
713 | length = strlen(dir); | ||
714 | |||
715 | if (length + 12 + 2 >= MAX_PATH) | ||
716 | return NULL; | ||
717 | |||
718 | it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length); | ||
719 | if (!it) | ||
720 | return NULL; | ||
721 | |||
722 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
723 | |||
724 | new_dir = _eina_file_win32_dir_new(dir); | ||
725 | if (!new_dir) | ||
726 | goto free_it; | ||
727 | |||
728 | it->handle = _eina_file_win32_first_file(new_dir, &it->data); | ||
729 | free(new_dir); | ||
730 | if (it->handle == INVALID_HANDLE_VALUE) | ||
731 | goto free_it; | ||
732 | |||
733 | memcpy(it->dir, dir, length + 1); | ||
734 | it->length = length; | ||
735 | _eina_file_win32_backslash_change(it->dir); | ||
736 | |||
737 | memcpy(it->info.path, dir, length); | ||
738 | if (dir[length - 1] == '\\') | ||
739 | it->info.name_start = length; | ||
740 | else | ||
741 | { | ||
742 | it->info.path[length] = '\\'; | ||
743 | it->info.name_start = length + 1; | ||
744 | } | ||
745 | _eina_file_win32_backslash_change(it->info.path); | ||
746 | |||
747 | it->iterator.version = EINA_ITERATOR_VERSION; | ||
748 | it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_direct_ls_iterator_next); | ||
749 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_direct_ls_iterator_container); | ||
750 | it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_direct_ls_iterator_free); | ||
751 | |||
752 | return &it->iterator; | ||
753 | |||
754 | free_it: | ||
755 | free(it); | ||
756 | |||
757 | return NULL; | ||
758 | } | ||
759 | |||
760 | EAPI Eina_Iterator * | ||
761 | eina_file_stat_ls(const char *dir) | ||
762 | { | ||
763 | return eina_file_direct_ls(dir); | ||
764 | } | ||
765 | |||
766 | EAPI Eina_File * | ||
767 | eina_file_open(const char *filename, Eina_Bool shared) | ||
768 | { | ||
769 | Eina_File *file; | ||
770 | Eina_File *n; | ||
771 | HANDLE handle; | ||
772 | HANDLE fm; | ||
773 | WIN32_FILE_ATTRIBUTE_DATA fad; | ||
774 | ULARGE_INTEGER length; | ||
775 | ULARGE_INTEGER mtime; | ||
776 | Eina_Bool create = EINA_FALSE; | ||
777 | |||
778 | /* FIXME: always open absolute path (need to fix filename according to current | ||
779 | directory) */ | ||
780 | |||
781 | /* FIXME: how to emulate shm_open ? Just OpenFileMapping ? */ | ||
782 | #if 0 | ||
783 | if (shared) | ||
784 | handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, | ||
785 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, | ||
786 | NULL); | ||
787 | else | ||
788 | #endif | ||
789 | handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, | ||
790 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, | ||
791 | NULL); | ||
792 | |||
793 | if (handle == INVALID_HANDLE_VALUE) | ||
794 | return NULL; | ||
795 | |||
796 | fm = CreateFileMapping(handle, NULL, PAGE_READONLY, 0, 0, NULL); | ||
797 | if (!fm) | ||
798 | goto close_handle; | ||
799 | |||
800 | if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad)) | ||
801 | goto close_fm; | ||
802 | |||
803 | length.u.LowPart = fad.nFileSizeLow; | ||
804 | length.u.HighPart = fad.nFileSizeHigh; | ||
805 | mtime.u.LowPart = fad.ftLastWriteTime.dwLowDateTime; | ||
806 | mtime.u.HighPart = fad.ftLastWriteTime.dwHighDateTime; | ||
807 | |||
808 | file = eina_hash_find(_eina_file_cache, filename); | ||
809 | if (file && | ||
810 | (file->mtime != mtime.QuadPart || file->length != length.QuadPart)) | ||
811 | { | ||
812 | create = EINA_TRUE; | ||
813 | |||
814 | if (file->refcount == 0) | ||
815 | { | ||
816 | _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file); | ||
817 | eina_hash_del(_eina_file_cache, file->filename, file); | ||
818 | |||
819 | file = NULL; | ||
820 | } | ||
821 | else if (!file->delete_me) | ||
822 | { | ||
823 | file->delete_me = EINA_TRUE; | ||
824 | _eina_file_cache_delete = eina_list_prepend(_eina_file_cache_delete, file); | ||
825 | } | ||
826 | } | ||
827 | |||
828 | if (!file || create) | ||
829 | { | ||
830 | n = calloc(1, sizeof (Eina_File)); | ||
831 | if (!n) | ||
832 | goto close_fm; | ||
833 | |||
834 | n->filename = eina_stringshare_add(filename); | ||
835 | n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length), | ||
836 | EINA_KEY_CMP(_eina_file_map_key_cmp), | ||
837 | EINA_KEY_HASH(_eina_file_map_key_hash), | ||
838 | EINA_FREE_CB(_eina_file_map_close), | ||
839 | 3); | ||
840 | n->rmap = eina_hash_pointer_new(NULL); | ||
841 | n->global_map = MAP_FAILED; | ||
842 | n->length = length.QuadPart; | ||
843 | n->mtime = mtime.QuadPart; | ||
844 | n->refcount = 0; | ||
845 | n->handle = handle; | ||
846 | n->fm = fm; | ||
847 | n->shared = shared; | ||
848 | n->delete_me = EINA_FALSE; | ||
849 | |||
850 | eina_hash_set(_eina_file_cache, filename, n); | ||
851 | } | ||
852 | else | ||
853 | { | ||
854 | CloseHandle(fm); | ||
855 | CloseHandle(handle); | ||
856 | |||
857 | n = file; | ||
858 | |||
859 | if (n->refcount == 0) | ||
860 | _eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n); | ||
861 | } | ||
862 | |||
863 | n->refcount++; | ||
864 | |||
865 | return n; | ||
866 | |||
867 | close_fm: | ||
868 | CloseHandle(fm); | ||
869 | close_handle: | ||
870 | CloseHandle(handle); | ||
871 | |||
872 | return NULL; | ||
873 | } | ||
874 | |||
875 | EAPI void | ||
876 | eina_file_close(Eina_File *file) | ||
877 | { | ||
878 | file->refcount--; | ||
879 | |||
880 | if (file->refcount != 0) return ; | ||
881 | |||
882 | if (file->delete_me) | ||
883 | { | ||
884 | _eina_file_cache_delete = eina_list_remove(_eina_file_cache_delete, file); | ||
885 | _eina_file_real_close(file); | ||
886 | } | ||
887 | else | ||
888 | { | ||
889 | _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file); | ||
890 | } | ||
891 | } | ||
892 | |||
893 | EAPI size_t | ||
894 | eina_file_size_get(Eina_File *file) | ||
895 | { | ||
896 | return file->length; | ||
897 | } | ||
898 | |||
899 | EAPI time_t | ||
900 | eina_file_mtime_get(Eina_File *file) | ||
901 | { | ||
902 | return file->mtime; | ||
903 | } | ||
904 | |||
905 | EAPI const char * | ||
906 | eina_file_filename_get(Eina_File *file) | ||
907 | { | ||
908 | return file->filename; | ||
909 | } | ||
910 | |||
911 | EAPI void * | ||
912 | eina_file_map_all(Eina_File *file, Eina_File_Populate rule __UNUSED__) | ||
913 | { | ||
914 | if (file->global_map == MAP_FAILED) | ||
915 | { | ||
916 | void *data; | ||
917 | |||
918 | data = MapViewOfFile(file->fm, FILE_MAP_READ, | ||
919 | 0, 0, file->length); | ||
920 | if (!data) | ||
921 | file->global_map = MAP_FAILED; | ||
922 | else | ||
923 | file->global_map = data; | ||
924 | } | ||
925 | |||
926 | if (file->global_map != MAP_FAILED) | ||
927 | { | ||
928 | file->global_refcount++; | ||
929 | return file->global_map; | ||
930 | } | ||
931 | |||
932 | return NULL; | ||
933 | } | ||
934 | |||
935 | EAPI void * | ||
936 | eina_file_map_new(Eina_File *file, Eina_File_Populate rule, | ||
937 | unsigned long int offset, unsigned long int length) | ||
938 | { | ||
939 | Eina_File_Map *map; | ||
940 | unsigned long int key[2]; | ||
941 | |||
942 | if (offset > file->length) | ||
943 | return NULL; | ||
944 | if (offset + length > file->length) | ||
945 | return NULL; | ||
946 | |||
947 | if (offset == 0 && length == file->length) | ||
948 | return eina_file_map_all(file, rule); | ||
949 | |||
950 | key[0] = offset; | ||
951 | key[1] = length; | ||
952 | |||
953 | map = eina_hash_find(file->map, &key); | ||
954 | if (!map) | ||
955 | { | ||
956 | void *data; | ||
957 | |||
958 | map = malloc(sizeof (Eina_File_Map)); | ||
959 | if (!map) return NULL; | ||
960 | |||
961 | data = MapViewOfFile(file->fm, FILE_MAP_READ, | ||
962 | offset & 0xffff0000, | ||
963 | offset & 0x0000ffff, | ||
964 | length); | ||
965 | if (!data) | ||
966 | map->map = MAP_FAILED; | ||
967 | else | ||
968 | map->map = data; | ||
969 | |||
970 | map->offset = offset; | ||
971 | map->length = length; | ||
972 | map->refcount = 0; | ||
973 | |||
974 | if (map->map == MAP_FAILED) | ||
975 | { | ||
976 | free(map); | ||
977 | return NULL; | ||
978 | } | ||
979 | |||
980 | eina_hash_add(file->map, &key, map); | ||
981 | eina_hash_direct_add(file->rmap, map->map, map); | ||
982 | } | ||
983 | |||
984 | map->refcount++; | ||
985 | |||
986 | return map->map; | ||
987 | } | ||
988 | |||
989 | EAPI void | ||
990 | eina_file_map_free(Eina_File *file, void *map) | ||
991 | { | ||
992 | if (file->global_map == map) | ||
993 | { | ||
994 | file->global_refcount--; | ||
995 | |||
996 | if (file->global_refcount > 0) return ; | ||
997 | |||
998 | /* FIXME: are we sure that file->global_map != MAP_FAILED ? */ | ||
999 | if (file->global_map != MAP_FAILED) | ||
1000 | UnmapViewOfFile(file->global_map); | ||
1001 | file->global_map = MAP_FAILED; | ||
1002 | } | ||
1003 | else | ||
1004 | { | ||
1005 | Eina_File_Map *em; | ||
1006 | unsigned long int key[2]; | ||
1007 | |||
1008 | em = eina_hash_find(file->rmap, &map); | ||
1009 | if (!em) return ; | ||
1010 | |||
1011 | em->refcount--; | ||
1012 | |||
1013 | if (em->refcount > 0) return ; | ||
1014 | |||
1015 | key[0] = em->offset; | ||
1016 | key[1] = em->length; | ||
1017 | |||
1018 | eina_hash_del(file->rmap, &map, em); | ||
1019 | eina_hash_del(file->map, &key, em); | ||
1020 | } | ||
1021 | } | ||