diff options
Diffstat (limited to 'libraries/eina/src/lib/eina_file_win32.c')
-rw-r--r-- | libraries/eina/src/lib/eina_file_win32.c | 1214 |
1 files changed, 0 insertions, 1214 deletions
diff --git a/libraries/eina/src/lib/eina_file_win32.c b/libraries/eina/src/lib/eina_file_win32.c deleted file mode 100644 index 5c20fdd..0000000 --- a/libraries/eina/src/lib/eina_file_win32.c +++ /dev/null | |||
@@ -1,1214 +0,0 @@ | |||
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 | #include <sys/types.h> | ||
41 | #include <sys/stat.h> | ||
42 | |||
43 | #define WIN32_LEAN_AND_MEAN | ||
44 | #include <windows.h> | ||
45 | #undef WIN32_LEAN_AND_MEAN | ||
46 | |||
47 | #include <Evil.h> | ||
48 | |||
49 | #include "eina_config.h" | ||
50 | #include "eina_private.h" | ||
51 | |||
52 | /* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */ | ||
53 | #include "eina_safety_checks.h" | ||
54 | #include "eina_file.h" | ||
55 | #include "eina_stringshare.h" | ||
56 | #include "eina_hash.h" | ||
57 | #include "eina_list.h" | ||
58 | #include "eina_lock.h" | ||
59 | #include "eina_log.h" | ||
60 | |||
61 | /*============================================================================* | ||
62 | * Local * | ||
63 | *============================================================================*/ | ||
64 | |||
65 | /** | ||
66 | * @cond LOCAL | ||
67 | */ | ||
68 | |||
69 | #ifndef EINA_LOG_COLOR_DEFAULT | ||
70 | #define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN | ||
71 | #endif | ||
72 | |||
73 | #ifdef ERR | ||
74 | #undef ERR | ||
75 | #endif | ||
76 | #define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__) | ||
77 | |||
78 | #ifdef WRN | ||
79 | #undef WRN | ||
80 | #endif | ||
81 | #define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__) | ||
82 | |||
83 | #ifdef DBG | ||
84 | #undef DBG | ||
85 | #endif | ||
86 | #define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__) | ||
87 | |||
88 | #ifdef MAP_FAILED | ||
89 | # undef MAP_FAILED | ||
90 | #endif | ||
91 | #define MAP_FAILED ((void *)-1) | ||
92 | |||
93 | typedef struct _Eina_File_Iterator Eina_File_Iterator; | ||
94 | typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator; | ||
95 | typedef struct _Eina_File_Map Eina_File_Map; | ||
96 | |||
97 | struct _Eina_File_Iterator | ||
98 | { | ||
99 | Eina_Iterator iterator; | ||
100 | |||
101 | WIN32_FIND_DATA data; | ||
102 | HANDLE handle; | ||
103 | size_t length; | ||
104 | Eina_Bool is_last : 1; | ||
105 | |||
106 | char dir[1]; | ||
107 | }; | ||
108 | |||
109 | struct _Eina_File_Direct_Iterator | ||
110 | { | ||
111 | Eina_Iterator iterator; | ||
112 | |||
113 | WIN32_FIND_DATA data; | ||
114 | HANDLE handle; | ||
115 | size_t length; | ||
116 | Eina_Bool is_last : 1; | ||
117 | |||
118 | Eina_File_Direct_Info info; | ||
119 | |||
120 | char dir[1]; | ||
121 | }; | ||
122 | |||
123 | struct _Eina_File | ||
124 | { | ||
125 | const char *filename; | ||
126 | |||
127 | Eina_Hash *map; | ||
128 | Eina_Hash *rmap; | ||
129 | void *global_map; | ||
130 | |||
131 | Eina_Lock lock; | ||
132 | |||
133 | ULONGLONG length; | ||
134 | ULONGLONG mtime; | ||
135 | |||
136 | int refcount; | ||
137 | int global_refcount; | ||
138 | |||
139 | HANDLE handle; | ||
140 | HANDLE fm; | ||
141 | |||
142 | Eina_Bool shared : 1; | ||
143 | Eina_Bool delete_me : 1; | ||
144 | }; | ||
145 | |||
146 | struct _Eina_File_Map | ||
147 | { | ||
148 | void *map; | ||
149 | |||
150 | unsigned long int offset; | ||
151 | unsigned long int length; | ||
152 | |||
153 | int refcount; | ||
154 | }; | ||
155 | |||
156 | static Eina_Hash *_eina_file_cache = NULL; | ||
157 | static Eina_Lock _eina_file_lock_cache; | ||
158 | |||
159 | static int _eina_file_log_dom = -1; | ||
160 | |||
161 | static void | ||
162 | _eina_file_win32_backslash_change(char *dir) | ||
163 | { | ||
164 | char *tmp; | ||
165 | |||
166 | tmp = dir; | ||
167 | while (*tmp) | ||
168 | { | ||
169 | if (*tmp == '/') *tmp = '\\'; | ||
170 | tmp++; | ||
171 | } | ||
172 | } | ||
173 | |||
174 | static Eina_Bool | ||
175 | _eina_file_win32_is_dir(const char *dir) | ||
176 | { | ||
177 | #ifdef UNICODE | ||
178 | wchar_t *wdir = NULL; | ||
179 | #endif | ||
180 | DWORD attr; | ||
181 | |||
182 | /* check if it's a directory */ | ||
183 | #ifdef UNICODE | ||
184 | wdir = evil_char_to_wchar(dir); | ||
185 | if (!wdir) | ||
186 | return EINA_FALSE; | ||
187 | |||
188 | attr = GetFileAttributes(wdir); | ||
189 | free(wdir); | ||
190 | #else | ||
191 | attr = GetFileAttributes(dir); | ||
192 | #endif | ||
193 | |||
194 | if (attr == 0xFFFFFFFF) | ||
195 | return EINA_FALSE; | ||
196 | |||
197 | if (!(attr & FILE_ATTRIBUTE_DIRECTORY)) | ||
198 | return EINA_FALSE; | ||
199 | |||
200 | return EINA_TRUE; | ||
201 | } | ||
202 | |||
203 | static char * | ||
204 | _eina_file_win32_dir_new(const char *dir) | ||
205 | { | ||
206 | char *new_dir; | ||
207 | size_t length; | ||
208 | |||
209 | length = strlen(dir); | ||
210 | |||
211 | new_dir = (char *)malloc(sizeof(char) * length + 5); | ||
212 | if (!new_dir) | ||
213 | return NULL; | ||
214 | |||
215 | memcpy(new_dir, dir, length); | ||
216 | memcpy(new_dir + length, "\\*.*", 5); | ||
217 | _eina_file_win32_backslash_change(new_dir); | ||
218 | |||
219 | return new_dir; | ||
220 | } | ||
221 | |||
222 | static HANDLE | ||
223 | _eina_file_win32_first_file(const char *dir, WIN32_FIND_DATA *fd) | ||
224 | { | ||
225 | HANDLE h; | ||
226 | #ifdef UNICODE | ||
227 | wchar_t *wdir = NULL; | ||
228 | |||
229 | wdir = evil_char_to_wchar(dir); | ||
230 | if (!wdir) | ||
231 | return NULL; | ||
232 | |||
233 | h = FindFirstFile(wdir, fd); | ||
234 | free(wdir); | ||
235 | #else | ||
236 | h = FindFirstFile(dir, fd); | ||
237 | #endif | ||
238 | |||
239 | if (!h) | ||
240 | return NULL; | ||
241 | |||
242 | while ((fd->cFileName[0] == '.') && | ||
243 | ((fd->cFileName[1] == '\0') || | ||
244 | ((fd->cFileName[1] == '.') && (fd->cFileName[2] == '\0')))) | ||
245 | { | ||
246 | if (!FindNextFile(h, fd)) | ||
247 | return NULL; | ||
248 | } | ||
249 | |||
250 | return h; | ||
251 | } | ||
252 | |||
253 | static Eina_Bool | ||
254 | _eina_file_win32_ls_iterator_next(Eina_File_Iterator *it, void **data) | ||
255 | { | ||
256 | #ifdef UNICODE | ||
257 | wchar_t *old_name; | ||
258 | #else | ||
259 | char *old_name; | ||
260 | #endif | ||
261 | char *name; | ||
262 | char *cname; | ||
263 | size_t length; | ||
264 | Eina_Bool is_last; | ||
265 | Eina_Bool res = EINA_TRUE; | ||
266 | |||
267 | if (it->handle == INVALID_HANDLE_VALUE) | ||
268 | return EINA_FALSE; | ||
269 | |||
270 | is_last = it->is_last; | ||
271 | #ifdef UNICODE | ||
272 | old_name = _wcsdup(it->data.cFileName); | ||
273 | #else | ||
274 | old_name = _strdup(it->data.cFileName); | ||
275 | #endif | ||
276 | if (!old_name) | ||
277 | return EINA_FALSE; | ||
278 | |||
279 | do { | ||
280 | if (!FindNextFile(it->handle, &it->data)) | ||
281 | { | ||
282 | if (GetLastError() == ERROR_NO_MORE_FILES) | ||
283 | it->is_last = EINA_TRUE; | ||
284 | else | ||
285 | res = EINA_FALSE; | ||
286 | } | ||
287 | } while ((it->data.cFileName[0] == '.') && | ||
288 | ((it->data.cFileName[1] == '\0') || | ||
289 | ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */ | ||
290 | |||
291 | #ifdef UNICODE | ||
292 | cname = evil_wchar_to_char(old_name); | ||
293 | if (!cname) | ||
294 | return EINA_FALSE; | ||
295 | #else | ||
296 | cname = old_name; | ||
297 | #endif | ||
298 | |||
299 | length = strlen(cname); | ||
300 | name = alloca(length + 2 + it->length); | ||
301 | |||
302 | memcpy(name, it->dir, it->length); | ||
303 | memcpy(name + it->length, "\\", 1); | ||
304 | memcpy(name + it->length + 1, cname, length + 1); | ||
305 | |||
306 | *data = (char *)eina_stringshare_add(name); | ||
307 | |||
308 | #ifdef UNICODE | ||
309 | free(cname); | ||
310 | #endif | ||
311 | free(old_name); | ||
312 | |||
313 | if (is_last) | ||
314 | res = EINA_FALSE; | ||
315 | |||
316 | return res; | ||
317 | } | ||
318 | |||
319 | static HANDLE | ||
320 | _eina_file_win32_ls_iterator_container(Eina_File_Iterator *it) | ||
321 | { | ||
322 | return it->handle; | ||
323 | } | ||
324 | |||
325 | static void | ||
326 | _eina_file_win32_ls_iterator_free(Eina_File_Iterator *it) | ||
327 | { | ||
328 | if (it->handle != INVALID_HANDLE_VALUE) | ||
329 | FindClose(it->handle); | ||
330 | |||
331 | EINA_MAGIC_SET(&it->iterator, 0); | ||
332 | free(it); | ||
333 | } | ||
334 | |||
335 | static Eina_Bool | ||
336 | _eina_file_win32_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data) | ||
337 | { | ||
338 | #ifdef UNICODE | ||
339 | wchar_t *old_name; | ||
340 | #else | ||
341 | char *old_name; | ||
342 | #endif | ||
343 | char *cname; | ||
344 | size_t length; | ||
345 | DWORD attr; | ||
346 | Eina_Bool is_last; | ||
347 | Eina_Bool res = EINA_TRUE; | ||
348 | |||
349 | if (it->handle == INVALID_HANDLE_VALUE) | ||
350 | return EINA_FALSE; | ||
351 | |||
352 | attr = it->data.dwFileAttributes; | ||
353 | is_last = it->is_last; | ||
354 | #ifdef UNICODE | ||
355 | old_name = _wcsdup(it->data.cFileName); | ||
356 | #else | ||
357 | old_name = _strdup(it->data.cFileName); | ||
358 | #endif | ||
359 | if (!old_name) | ||
360 | return EINA_FALSE; | ||
361 | |||
362 | do { | ||
363 | if (!FindNextFile(it->handle, &it->data)) | ||
364 | { | ||
365 | if (GetLastError() == ERROR_NO_MORE_FILES) | ||
366 | it->is_last = EINA_TRUE; | ||
367 | else | ||
368 | res = EINA_FALSE; | ||
369 | } | ||
370 | |||
371 | #ifdef UNICODE | ||
372 | length = wcslen(old_name); | ||
373 | #else | ||
374 | length = strlen(old_name); | ||
375 | #endif | ||
376 | if (it->info.name_start + length + 1 >= PATH_MAX) | ||
377 | { | ||
378 | free(old_name); | ||
379 | #ifdef UNICODE | ||
380 | old_name = _wcsdup(it->data.cFileName); | ||
381 | #else | ||
382 | old_name = _strdup(it->data.cFileName); | ||
383 | #endif | ||
384 | continue; | ||
385 | } | ||
386 | |||
387 | } while ((it->data.cFileName[0] == '.') && | ||
388 | ((it->data.cFileName[1] == '\0') || | ||
389 | ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */ | ||
390 | |||
391 | #ifdef UNICODE | ||
392 | cname = evil_wchar_to_char(old_name); | ||
393 | if (!cname) | ||
394 | return EINA_FALSE; | ||
395 | #else | ||
396 | cname = old_name; | ||
397 | #endif | ||
398 | |||
399 | memcpy(it->info.path + it->info.name_start, cname, length); | ||
400 | it->info.name_length = length; | ||
401 | it->info.path_length = it->info.name_start + length; | ||
402 | it->info.path[it->info.path_length] = '\0'; | ||
403 | |||
404 | if (attr & FILE_ATTRIBUTE_DIRECTORY) | ||
405 | it->info.type = EINA_FILE_DIR; | ||
406 | else if (attr & FILE_ATTRIBUTE_REPARSE_POINT) | ||
407 | it->info.type = EINA_FILE_LNK; | ||
408 | else if (attr & (FILE_ATTRIBUTE_ARCHIVE | | ||
409 | FILE_ATTRIBUTE_COMPRESSED | | ||
410 | FILE_ATTRIBUTE_COMPRESSED | | ||
411 | FILE_ATTRIBUTE_HIDDEN | | ||
412 | FILE_ATTRIBUTE_NORMAL | | ||
413 | FILE_ATTRIBUTE_SPARSE_FILE | | ||
414 | FILE_ATTRIBUTE_TEMPORARY)) | ||
415 | it->info.type = EINA_FILE_REG; | ||
416 | else | ||
417 | it->info.type = EINA_FILE_UNKNOWN; | ||
418 | |||
419 | *data = &it->info; | ||
420 | |||
421 | #ifdef UNICODE | ||
422 | free(cname); | ||
423 | #endif | ||
424 | |||
425 | free(old_name); | ||
426 | |||
427 | if (is_last) | ||
428 | res = EINA_FALSE; | ||
429 | |||
430 | return res; | ||
431 | } | ||
432 | |||
433 | static HANDLE | ||
434 | _eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it) | ||
435 | { | ||
436 | return it->handle; | ||
437 | } | ||
438 | |||
439 | static void | ||
440 | _eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it) | ||
441 | { | ||
442 | if (it->handle != INVALID_HANDLE_VALUE) | ||
443 | FindClose(it->handle); | ||
444 | |||
445 | EINA_MAGIC_SET(&it->iterator, 0); | ||
446 | free(it); | ||
447 | } | ||
448 | |||
449 | static void | ||
450 | _eina_file_real_close(Eina_File *file) | ||
451 | { | ||
452 | eina_hash_free(file->rmap); | ||
453 | eina_hash_free(file->map); | ||
454 | |||
455 | if (file->global_map != MAP_FAILED) | ||
456 | UnmapViewOfFile(file->global_map); | ||
457 | |||
458 | CloseHandle(file->fm); | ||
459 | CloseHandle(file->handle); | ||
460 | |||
461 | free(file); | ||
462 | } | ||
463 | |||
464 | static void | ||
465 | _eina_file_map_close(Eina_File_Map *map) | ||
466 | { | ||
467 | if (map->map != MAP_FAILED) | ||
468 | UnmapViewOfFile(map->map); | ||
469 | free(map); | ||
470 | } | ||
471 | |||
472 | static unsigned int | ||
473 | _eina_file_map_key_length(const void *key __UNUSED__) | ||
474 | { | ||
475 | return sizeof (unsigned long int) * 2; | ||
476 | } | ||
477 | |||
478 | static int | ||
479 | _eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__, | ||
480 | const unsigned long int *key2, int key2_length __UNUSED__) | ||
481 | { | ||
482 | if (key1[0] - key2[0] == 0) return key1[1] - key2[1]; | ||
483 | return key1[0] - key2[0]; | ||
484 | } | ||
485 | |||
486 | static int | ||
487 | _eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__) | ||
488 | { | ||
489 | return eina_hash_int64(&key[0], sizeof (unsigned long int)) | ||
490 | ^ eina_hash_int64(&key[1], sizeof (unsigned long int)); | ||
491 | } | ||
492 | |||
493 | static char * | ||
494 | _eina_file_win32_escape(const char *path, size_t *length) | ||
495 | { | ||
496 | char *result = strdup(path ? path : ""); | ||
497 | char *p = result; | ||
498 | char *q = result; | ||
499 | size_t len; | ||
500 | |||
501 | if (!result) | ||
502 | return NULL; | ||
503 | |||
504 | if (length) len = *length; | ||
505 | else len = strlen(result); | ||
506 | |||
507 | while ((p = strchr(p, '/'))) | ||
508 | { | ||
509 | // remove double `/' | ||
510 | if (p[1] == '/') | ||
511 | { | ||
512 | memmove(p, p + 1, --len - (p - result)); | ||
513 | result[len] = '\0'; | ||
514 | } | ||
515 | else | ||
516 | if (p[1] == '.' | ||
517 | && p[2] == '.') | ||
518 | { | ||
519 | // remove `/../' | ||
520 | if (p[3] == '/') | ||
521 | { | ||
522 | char tmp; | ||
523 | |||
524 | len -= p + 3 - q; | ||
525 | memmove(q, p + 3, len - (q - result)); | ||
526 | result[len] = '\0'; | ||
527 | p = q; | ||
528 | |||
529 | /* Update q correctly. */ | ||
530 | tmp = *p; | ||
531 | *p = '\0'; | ||
532 | q = strrchr(result, '/'); | ||
533 | if (!q) q = result; | ||
534 | *p = tmp; | ||
535 | } | ||
536 | else | ||
537 | // remove '/..$' | ||
538 | if (p[3] == '\0') | ||
539 | { | ||
540 | len -= p + 2 - q; | ||
541 | result[len] = '\0'; | ||
542 | q = p; | ||
543 | ++p; | ||
544 | } | ||
545 | else | ||
546 | { | ||
547 | q = p; | ||
548 | ++p; | ||
549 | } | ||
550 | } | ||
551 | else | ||
552 | { | ||
553 | q = p; | ||
554 | ++p; | ||
555 | } | ||
556 | } | ||
557 | |||
558 | if (length) | ||
559 | *length = len; | ||
560 | |||
561 | return result; | ||
562 | } | ||
563 | |||
564 | |||
565 | /** | ||
566 | * @endcond | ||
567 | */ | ||
568 | |||
569 | /*============================================================================* | ||
570 | * Global * | ||
571 | *============================================================================*/ | ||
572 | |||
573 | Eina_Bool | ||
574 | eina_file_init(void) | ||
575 | { | ||
576 | _eina_file_log_dom = eina_log_domain_register("eina_file", | ||
577 | EINA_LOG_COLOR_DEFAULT); | ||
578 | if (_eina_file_log_dom < 0) | ||
579 | { | ||
580 | EINA_LOG_ERR("Could not register log domain: eina_file"); | ||
581 | return EINA_FALSE; | ||
582 | } | ||
583 | |||
584 | _eina_file_cache = eina_hash_string_djb2_new(NULL); | ||
585 | if (!_eina_file_cache) | ||
586 | { | ||
587 | ERR("Could not create cache."); | ||
588 | eina_log_domain_unregister(_eina_file_log_dom); | ||
589 | _eina_file_log_dom = -1; | ||
590 | return EINA_FALSE; | ||
591 | } | ||
592 | |||
593 | eina_lock_new(&_eina_file_lock_cache); | ||
594 | |||
595 | return EINA_TRUE; | ||
596 | } | ||
597 | |||
598 | Eina_Bool | ||
599 | eina_file_shutdown(void) | ||
600 | { | ||
601 | if (eina_hash_population(_eina_file_cache) > 0) | ||
602 | { | ||
603 | Eina_Iterator *it; | ||
604 | const char *key; | ||
605 | |||
606 | it = eina_hash_iterator_key_new(_eina_file_cache); | ||
607 | EINA_ITERATOR_FOREACH(it, key) | ||
608 | ERR("File [%s] still open !", key); | ||
609 | eina_iterator_free(it); | ||
610 | } | ||
611 | |||
612 | eina_hash_free(_eina_file_cache); | ||
613 | |||
614 | eina_lock_free(&_eina_file_lock_cache); | ||
615 | |||
616 | eina_log_domain_unregister(_eina_file_log_dom); | ||
617 | _eina_file_log_dom = -1; | ||
618 | return EINA_TRUE; | ||
619 | } | ||
620 | |||
621 | /*============================================================================* | ||
622 | * API * | ||
623 | *============================================================================*/ | ||
624 | |||
625 | |||
626 | EAPI char * | ||
627 | eina_file_path_sanitize(const char *path) | ||
628 | { | ||
629 | char *result = NULL; | ||
630 | size_t len; | ||
631 | |||
632 | if (!path) return NULL; | ||
633 | |||
634 | len = strlen(path); | ||
635 | if (len < 3) return NULL; | ||
636 | |||
637 | if (!evil_path_is_absolute(path)) | ||
638 | { | ||
639 | DWORD l; | ||
640 | |||
641 | l = GetCurrentDirectory(0, NULL); | ||
642 | if (l > 0) | ||
643 | { | ||
644 | char *cwd; | ||
645 | DWORD l2; | ||
646 | |||
647 | cwd = alloca(sizeof(char) * (l + 1)); | ||
648 | l2 = GetCurrentDirectory(l + 1, cwd); | ||
649 | if (l2 == l) | ||
650 | { | ||
651 | char *tmp; | ||
652 | |||
653 | len += l + 2; | ||
654 | tmp = alloca(sizeof (char) * len); | ||
655 | snprintf(tmp, len, "%s/%s", cwd, path); | ||
656 | tmp[len - 1] = '\0'; | ||
657 | result = tmp; | ||
658 | } | ||
659 | } | ||
660 | } | ||
661 | |||
662 | return _eina_file_win32_escape(result ? result : path, &len); | ||
663 | } | ||
664 | |||
665 | EAPI Eina_Bool | ||
666 | eina_file_dir_list(const char *dir, | ||
667 | Eina_Bool recursive, | ||
668 | Eina_File_Dir_List_Cb cb, | ||
669 | void *data) | ||
670 | { | ||
671 | WIN32_FIND_DATA file; | ||
672 | HANDLE h; | ||
673 | char *new_dir; | ||
674 | |||
675 | EINA_SAFETY_ON_NULL_RETURN_VAL(cb, EINA_FALSE); | ||
676 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE); | ||
677 | EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE); | ||
678 | |||
679 | if (!_eina_file_win32_is_dir(dir)) | ||
680 | return EINA_FALSE; | ||
681 | |||
682 | new_dir = _eina_file_win32_dir_new(dir); | ||
683 | if (!new_dir) | ||
684 | return EINA_FALSE; | ||
685 | |||
686 | h = _eina_file_win32_first_file(new_dir, &file); | ||
687 | |||
688 | if (h == INVALID_HANDLE_VALUE) | ||
689 | return EINA_FALSE; | ||
690 | |||
691 | do | ||
692 | { | ||
693 | char *filename; | ||
694 | |||
695 | # ifdef UNICODE | ||
696 | filename = evil_wchar_to_char(file.cFileName); | ||
697 | # else | ||
698 | filename = file.cFileName; | ||
699 | # endif /* ! UNICODE */ | ||
700 | if (!strcmp(filename, ".") || !strcmp(filename, "..")) | ||
701 | continue; | ||
702 | |||
703 | cb(filename, dir, data); | ||
704 | |||
705 | if (recursive == EINA_TRUE) | ||
706 | { | ||
707 | char *path; | ||
708 | |||
709 | path = alloca(strlen(dir) + strlen(filename) + 2); | ||
710 | strcpy(path, dir); | ||
711 | strcat(path, "/"); | ||
712 | strcat(path, filename); | ||
713 | |||
714 | if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) | ||
715 | continue; | ||
716 | |||
717 | eina_file_dir_list(path, recursive, cb, data); | ||
718 | } | ||
719 | |||
720 | # ifdef UNICODE | ||
721 | free(filename); | ||
722 | # endif /* UNICODE */ | ||
723 | |||
724 | } while (FindNextFile(h, &file)); | ||
725 | FindClose(h); | ||
726 | |||
727 | return EINA_TRUE; | ||
728 | } | ||
729 | |||
730 | EAPI Eina_Array * | ||
731 | eina_file_split(char *path) | ||
732 | { | ||
733 | Eina_Array *ea; | ||
734 | char *current; | ||
735 | size_t length; | ||
736 | |||
737 | EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); | ||
738 | |||
739 | ea = eina_array_new(16); | ||
740 | |||
741 | if (!ea) | ||
742 | return NULL; | ||
743 | |||
744 | for (current = strchr(path, '\\'); | ||
745 | current; | ||
746 | path = current + 1, current = strchr(path, '\\')) | ||
747 | { | ||
748 | length = current - path; | ||
749 | |||
750 | if (length <= 0) | ||
751 | continue; | ||
752 | |||
753 | eina_array_push(ea, path); | ||
754 | *current = '\0'; | ||
755 | } | ||
756 | |||
757 | if (*path != '\0') | ||
758 | eina_array_push(ea, path); | ||
759 | |||
760 | return ea; | ||
761 | } | ||
762 | |||
763 | EAPI Eina_Iterator * | ||
764 | eina_file_ls(const char *dir) | ||
765 | { | ||
766 | Eina_File_Iterator *it; | ||
767 | char *new_dir; | ||
768 | size_t length; | ||
769 | |||
770 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); | ||
771 | |||
772 | if (!dir || !*dir) | ||
773 | return NULL; | ||
774 | |||
775 | if (!_eina_file_win32_is_dir(dir)) | ||
776 | return NULL; | ||
777 | |||
778 | length = strlen(dir); | ||
779 | |||
780 | it = calloc(1, sizeof (Eina_File_Iterator) + length); | ||
781 | if (!it) | ||
782 | return NULL; | ||
783 | |||
784 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
785 | |||
786 | new_dir = _eina_file_win32_dir_new(dir); | ||
787 | if (!new_dir) | ||
788 | goto free_it; | ||
789 | |||
790 | it->handle = _eina_file_win32_first_file(new_dir, &it->data); | ||
791 | free(new_dir); | ||
792 | if (it->handle == INVALID_HANDLE_VALUE) | ||
793 | goto free_it; | ||
794 | |||
795 | memcpy(it->dir, dir, length + 1); | ||
796 | if (dir[length - 1] != '\\') | ||
797 | it->length = length; | ||
798 | else | ||
799 | it->length = length - 1; | ||
800 | _eina_file_win32_backslash_change(it->dir); | ||
801 | |||
802 | it->iterator.version = EINA_ITERATOR_VERSION; | ||
803 | it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_ls_iterator_next); | ||
804 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_ls_iterator_container); | ||
805 | it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_ls_iterator_free); | ||
806 | |||
807 | return &it->iterator; | ||
808 | |||
809 | free_it: | ||
810 | free(it); | ||
811 | |||
812 | return NULL; | ||
813 | } | ||
814 | |||
815 | EAPI Eina_Iterator * | ||
816 | eina_file_direct_ls(const char *dir) | ||
817 | { | ||
818 | Eina_File_Direct_Iterator *it; | ||
819 | char *new_dir; | ||
820 | size_t length; | ||
821 | |||
822 | EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); | ||
823 | |||
824 | if (!dir || !*dir) | ||
825 | return NULL; | ||
826 | |||
827 | length = strlen(dir); | ||
828 | |||
829 | if (length + 12 + 2 >= MAX_PATH) | ||
830 | return NULL; | ||
831 | |||
832 | it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length); | ||
833 | if (!it) | ||
834 | return NULL; | ||
835 | |||
836 | EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR); | ||
837 | |||
838 | new_dir = _eina_file_win32_dir_new(dir); | ||
839 | if (!new_dir) | ||
840 | goto free_it; | ||
841 | |||
842 | it->handle = _eina_file_win32_first_file(new_dir, &it->data); | ||
843 | free(new_dir); | ||
844 | if (it->handle == INVALID_HANDLE_VALUE) | ||
845 | goto free_it; | ||
846 | |||
847 | memcpy(it->dir, dir, length + 1); | ||
848 | it->length = length; | ||
849 | _eina_file_win32_backslash_change(it->dir); | ||
850 | |||
851 | memcpy(it->info.path, dir, length); | ||
852 | if (dir[length - 1] == '\\') | ||
853 | it->info.name_start = length; | ||
854 | else | ||
855 | { | ||
856 | it->info.path[length] = '\\'; | ||
857 | it->info.name_start = length + 1; | ||
858 | } | ||
859 | _eina_file_win32_backslash_change(it->info.path); | ||
860 | |||
861 | it->iterator.version = EINA_ITERATOR_VERSION; | ||
862 | it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_direct_ls_iterator_next); | ||
863 | it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_direct_ls_iterator_container); | ||
864 | it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_direct_ls_iterator_free); | ||
865 | |||
866 | return &it->iterator; | ||
867 | |||
868 | free_it: | ||
869 | free(it); | ||
870 | |||
871 | return NULL; | ||
872 | } | ||
873 | |||
874 | EAPI Eina_Iterator * | ||
875 | eina_file_stat_ls(const char *dir) | ||
876 | { | ||
877 | return eina_file_direct_ls(dir); | ||
878 | } | ||
879 | |||
880 | EAPI Eina_File * | ||
881 | eina_file_open(const char *path, Eina_Bool shared) | ||
882 | { | ||
883 | Eina_File *file; | ||
884 | Eina_File *n; | ||
885 | char *filename; | ||
886 | HANDLE handle; | ||
887 | HANDLE fm; | ||
888 | WIN32_FILE_ATTRIBUTE_DATA fad; | ||
889 | ULARGE_INTEGER length; | ||
890 | ULARGE_INTEGER mtime; | ||
891 | |||
892 | EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); | ||
893 | |||
894 | filename = eina_file_path_sanitize(path); | ||
895 | if (!filename) return NULL; | ||
896 | |||
897 | /* FIXME: how to emulate shm_open ? Just OpenFileMapping ? */ | ||
898 | #if 0 | ||
899 | if (shared) | ||
900 | handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, | ||
901 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, | ||
902 | NULL); | ||
903 | else | ||
904 | #endif | ||
905 | handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, | ||
906 | NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, | ||
907 | NULL); | ||
908 | |||
909 | if (handle == INVALID_HANDLE_VALUE) | ||
910 | return NULL; | ||
911 | |||
912 | fm = CreateFileMapping(handle, NULL, PAGE_READONLY, 0, 0, NULL); | ||
913 | if (!fm) | ||
914 | goto close_handle; | ||
915 | |||
916 | if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad)) | ||
917 | goto close_fm; | ||
918 | |||
919 | length.u.LowPart = fad.nFileSizeLow; | ||
920 | length.u.HighPart = fad.nFileSizeHigh; | ||
921 | mtime.u.LowPart = fad.ftLastWriteTime.dwLowDateTime; | ||
922 | mtime.u.HighPart = fad.ftLastWriteTime.dwHighDateTime; | ||
923 | |||
924 | eina_lock_take(&_eina_file_lock_cache); | ||
925 | |||
926 | file = eina_hash_find(_eina_file_cache, filename); | ||
927 | if (file && | ||
928 | (file->mtime != mtime.QuadPart || file->length != length.QuadPart)) | ||
929 | { | ||
930 | file->delete_me = EINA_TRUE; | ||
931 | eina_hash_del(_eina_file_cache, file->filename, file); | ||
932 | _eina_file_real_close(file); | ||
933 | file = NULL; | ||
934 | } | ||
935 | |||
936 | if (!file) | ||
937 | { | ||
938 | n = malloc(sizeof (Eina_File) + strlen(filename) + 1); | ||
939 | if (!n) | ||
940 | { | ||
941 | eina_lock_release(&_eina_file_lock_cache); | ||
942 | goto close_fm; | ||
943 | } | ||
944 | |||
945 | n->filename = (char*) (n + 1); | ||
946 | strcpy((char*) n->filename, filename); | ||
947 | n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length), | ||
948 | EINA_KEY_CMP(_eina_file_map_key_cmp), | ||
949 | EINA_KEY_HASH(_eina_file_map_key_hash), | ||
950 | EINA_FREE_CB(_eina_file_map_close), | ||
951 | 3); | ||
952 | n->rmap = eina_hash_pointer_new(NULL); | ||
953 | n->global_map = MAP_FAILED; | ||
954 | n->global_refcount = 0; | ||
955 | n->length = length.QuadPart; | ||
956 | n->mtime = mtime.QuadPart; | ||
957 | n->refcount = 0; | ||
958 | n->handle = handle; | ||
959 | n->fm = fm; | ||
960 | n->shared = shared; | ||
961 | n->delete_me = EINA_FALSE; | ||
962 | eina_lock_new(&n->lock); | ||
963 | eina_hash_direct_add(_eina_file_cache, n->filename, n); | ||
964 | } | ||
965 | else | ||
966 | { | ||
967 | CloseHandle(fm); | ||
968 | CloseHandle(handle); | ||
969 | |||
970 | n = file; | ||
971 | } | ||
972 | eina_lock_take(&n->lock); | ||
973 | n->refcount++; | ||
974 | eina_lock_release(&n->lock); | ||
975 | |||
976 | eina_lock_release(&_eina_file_lock_cache); | ||
977 | |||
978 | free(filename); | ||
979 | |||
980 | return n; | ||
981 | |||
982 | close_fm: | ||
983 | CloseHandle(fm); | ||
984 | close_handle: | ||
985 | CloseHandle(handle); | ||
986 | |||
987 | return NULL; | ||
988 | } | ||
989 | |||
990 | EAPI void | ||
991 | eina_file_close(Eina_File *file) | ||
992 | { | ||
993 | EINA_SAFETY_ON_NULL_RETURN(file); | ||
994 | |||
995 | eina_lock_take(&file->lock); | ||
996 | file->refcount--; | ||
997 | eina_lock_release(&file->lock); | ||
998 | |||
999 | if (file->refcount != 0) return ; | ||
1000 | eina_lock_take(&_eina_file_lock_cache); | ||
1001 | |||
1002 | eina_hash_del(_eina_file_cache, file->filename, file); | ||
1003 | _eina_file_real_close(file); | ||
1004 | |||
1005 | eina_lock_release(&_eina_file_lock_cache); | ||
1006 | } | ||
1007 | |||
1008 | EAPI size_t | ||
1009 | eina_file_size_get(Eina_File *file) | ||
1010 | { | ||
1011 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0); | ||
1012 | return file->length; | ||
1013 | } | ||
1014 | |||
1015 | EAPI time_t | ||
1016 | eina_file_mtime_get(Eina_File *file) | ||
1017 | { | ||
1018 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0); | ||
1019 | return file->mtime; | ||
1020 | } | ||
1021 | |||
1022 | EAPI const char * | ||
1023 | eina_file_filename_get(Eina_File *file) | ||
1024 | { | ||
1025 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1026 | return file->filename; | ||
1027 | } | ||
1028 | |||
1029 | EAPI Eina_Iterator *eina_file_xattr_get(Eina_File *file __UNUSED__) | ||
1030 | { | ||
1031 | return NULL; | ||
1032 | } | ||
1033 | |||
1034 | EAPI Eina_Iterator *eina_file_xattr_value_get(Eina_File *file __UNUSED__) | ||
1035 | { | ||
1036 | return NULL; | ||
1037 | } | ||
1038 | |||
1039 | EAPI void * | ||
1040 | eina_file_map_all(Eina_File *file, Eina_File_Populate rule __UNUSED__) | ||
1041 | { | ||
1042 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1043 | |||
1044 | eina_lock_take(&file->lock); | ||
1045 | if (file->global_map == MAP_FAILED) | ||
1046 | { | ||
1047 | void *data; | ||
1048 | |||
1049 | data = MapViewOfFile(file->fm, FILE_MAP_READ, | ||
1050 | 0, 0, file->length); | ||
1051 | if (!data) | ||
1052 | file->global_map = MAP_FAILED; | ||
1053 | else | ||
1054 | file->global_map = data; | ||
1055 | } | ||
1056 | |||
1057 | if (file->global_map != MAP_FAILED) | ||
1058 | { | ||
1059 | file->global_refcount++; | ||
1060 | return file->global_map; | ||
1061 | } | ||
1062 | |||
1063 | eina_lock_release(&file->lock); | ||
1064 | return NULL; | ||
1065 | } | ||
1066 | |||
1067 | EAPI void * | ||
1068 | eina_file_map_new(Eina_File *file, Eina_File_Populate rule, | ||
1069 | unsigned long int offset, unsigned long int length) | ||
1070 | { | ||
1071 | Eina_File_Map *map; | ||
1072 | unsigned long int key[2]; | ||
1073 | |||
1074 | EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); | ||
1075 | |||
1076 | if (offset > file->length) | ||
1077 | return NULL; | ||
1078 | if (offset + length > file->length) | ||
1079 | return NULL; | ||
1080 | |||
1081 | if (offset == 0 && length == file->length) | ||
1082 | return eina_file_map_all(file, rule); | ||
1083 | |||
1084 | key[0] = offset; | ||
1085 | key[1] = length; | ||
1086 | |||
1087 | eina_lock_take(&file->lock); | ||
1088 | |||
1089 | map = eina_hash_find(file->map, &key); | ||
1090 | if (!map) | ||
1091 | { | ||
1092 | void *data; | ||
1093 | |||
1094 | map = malloc(sizeof (Eina_File_Map)); | ||
1095 | if (!map) | ||
1096 | { | ||
1097 | eina_lock_release(&file->lock); | ||
1098 | return NULL; | ||
1099 | } | ||
1100 | |||
1101 | data = MapViewOfFile(file->fm, FILE_MAP_READ, | ||
1102 | offset & 0xffff0000, | ||
1103 | offset & 0x0000ffff, | ||
1104 | length); | ||
1105 | if (!data) | ||
1106 | map->map = MAP_FAILED; | ||
1107 | else | ||
1108 | map->map = data; | ||
1109 | |||
1110 | map->offset = offset; | ||
1111 | map->length = length; | ||
1112 | map->refcount = 0; | ||
1113 | |||
1114 | if (map->map == MAP_FAILED) | ||
1115 | { | ||
1116 | free(map); | ||
1117 | eina_lock_release(&file->lock); | ||
1118 | return NULL; | ||
1119 | } | ||
1120 | |||
1121 | eina_hash_add(file->map, &key, map); | ||
1122 | eina_hash_direct_add(file->rmap, map->map, map); | ||
1123 | } | ||
1124 | |||
1125 | map->refcount++; | ||
1126 | |||
1127 | eina_lock_release(&file->lock); | ||
1128 | |||
1129 | return map->map; | ||
1130 | } | ||
1131 | |||
1132 | EAPI void | ||
1133 | eina_file_map_free(Eina_File *file, void *map) | ||
1134 | { | ||
1135 | EINA_SAFETY_ON_NULL_RETURN(file); | ||
1136 | |||
1137 | eina_lock_take(&file->lock); | ||
1138 | |||
1139 | if (file->global_map == map) | ||
1140 | { | ||
1141 | file->global_refcount--; | ||
1142 | |||
1143 | if (file->global_refcount > 0) goto on_exit; | ||
1144 | |||
1145 | UnmapViewOfFile(file->global_map); | ||
1146 | file->global_map = MAP_FAILED; | ||
1147 | } | ||
1148 | else | ||
1149 | { | ||
1150 | Eina_File_Map *em; | ||
1151 | unsigned long int key[2]; | ||
1152 | |||
1153 | em = eina_hash_find(file->rmap, &map); | ||
1154 | if (!em) goto on_exit; | ||
1155 | |||
1156 | em->refcount--; | ||
1157 | |||
1158 | if (em->refcount > 0) goto on_exit; | ||
1159 | |||
1160 | key[0] = em->offset; | ||
1161 | key[1] = em->length; | ||
1162 | |||
1163 | eina_hash_del(file->rmap, &map, em); | ||
1164 | eina_hash_del(file->map, &key, em); | ||
1165 | } | ||
1166 | |||
1167 | on_exit: | ||
1168 | eina_lock_release(&file->lock); | ||
1169 | } | ||
1170 | |||
1171 | EAPI int | ||
1172 | eina_file_statat(void *container __UNUSED__, Eina_File_Direct_Info *info, Eina_Stat *st) | ||
1173 | { | ||
1174 | struct __stat64 buf; | ||
1175 | |||
1176 | EINA_SAFETY_ON_NULL_RETURN_VAL(info, -1); | ||
1177 | EINA_SAFETY_ON_NULL_RETURN_VAL(st, -1); | ||
1178 | |||
1179 | if (stat64(info->path, &buf)) | ||
1180 | { | ||
1181 | if (info->type != EINA_FILE_LNK) | ||
1182 | info->type = EINA_FILE_UNKNOWN; | ||
1183 | return -1; | ||
1184 | } | ||
1185 | |||
1186 | if (info->type == EINA_FILE_UNKNOWN) | ||
1187 | { | ||
1188 | if (S_ISREG(buf.st_mode)) | ||
1189 | info->type = EINA_FILE_REG; | ||
1190 | else if (S_ISDIR(buf.st_mode)) | ||
1191 | info->type = EINA_FILE_DIR; | ||
1192 | else | ||
1193 | info->type = EINA_FILE_UNKNOWN; | ||
1194 | } | ||
1195 | |||
1196 | st->dev = buf.st_dev; | ||
1197 | st->ino = buf.st_ino; | ||
1198 | st->mode = buf.st_mode; | ||
1199 | st->nlink = buf.st_nlink; | ||
1200 | st->uid = buf.st_uid; | ||
1201 | st->gid = buf.st_gid; | ||
1202 | st->rdev = buf.st_rdev; | ||
1203 | st->size = buf.st_size; | ||
1204 | st->blksize = 0; | ||
1205 | st->blocks = 0; | ||
1206 | st->atime = buf.st_atime; | ||
1207 | st->mtime = buf.st_mtime; | ||
1208 | st->ctime = buf.st_ctime; | ||
1209 | st->atimensec = 0; | ||
1210 | st->mtimensec = 0; | ||
1211 | st->ctimensec = 0; | ||
1212 | |||
1213 | return 0; | ||
1214 | } | ||