aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/eina/src/lib/eina_file_win32.c
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/eina/src/lib/eina_file_win32.c')
-rw-r--r--libraries/eina/src/lib/eina_file_win32.c1021
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
35extern "C"
36# endif
37void *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
88typedef struct _Eina_File_Iterator Eina_File_Iterator;
89typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
90typedef struct _Eina_File_Map Eina_File_Map;
91
92struct _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
104struct _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
118struct _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
139struct _Eina_File_Map
140{
141 void *map;
142
143 unsigned long int offset;
144 unsigned long int length;
145
146 int refcount;
147};
148
149static Eina_Hash *_eina_file_cache = NULL;
150static Eina_List *_eina_file_cache_lru = NULL;
151static Eina_List *_eina_file_cache_delete = NULL;
152
153static int _eina_file_log_dom = -1;
154
155static 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
168static 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
197static 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
216static 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
247static 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
313static HANDLE
314_eina_file_win32_ls_iterator_container(Eina_File_Iterator *it)
315{
316 return it->handle;
317}
318
319static 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
329static 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
427static HANDLE
428_eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
429{
430 return it->handle;
431}
432
433static 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
443static 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
460static 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
468static unsigned int
469_eina_file_map_key_length(const void *key __UNUSED__)
470{
471 return sizeof (unsigned long int) * 2;
472}
473
474static 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
482static 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
489Eina_Bool
490eina_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
512Eina_Bool
513eina_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
555EAPI Eina_Bool
556eina_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
620EAPI Eina_Array *
621eina_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
653EAPI Eina_Iterator *
654eina_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
703EAPI Eina_Iterator *
704eina_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
760EAPI Eina_Iterator *
761eina_file_stat_ls(const char *dir)
762{
763 return eina_file_direct_ls(dir);
764}
765
766EAPI Eina_File *
767eina_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
875EAPI void
876eina_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
893EAPI size_t
894eina_file_size_get(Eina_File *file)
895{
896 return file->length;
897}
898
899EAPI time_t
900eina_file_mtime_get(Eina_File *file)
901{
902 return file->mtime;
903}
904
905EAPI const char *
906eina_file_filename_get(Eina_File *file)
907{
908 return file->filename;
909}
910
911EAPI void *
912eina_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
935EAPI void *
936eina_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
989EAPI void
990eina_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}