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.c1214
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
35extern "C"
36# endif
37void *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
93typedef struct _Eina_File_Iterator Eina_File_Iterator;
94typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
95typedef struct _Eina_File_Map Eina_File_Map;
96
97struct _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
109struct _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
123struct _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
146struct _Eina_File_Map
147{
148 void *map;
149
150 unsigned long int offset;
151 unsigned long int length;
152
153 int refcount;
154};
155
156static Eina_Hash *_eina_file_cache = NULL;
157static Eina_Lock _eina_file_lock_cache;
158
159static int _eina_file_log_dom = -1;
160
161static 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
174static 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
203static 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
222static 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
253static 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
319static HANDLE
320_eina_file_win32_ls_iterator_container(Eina_File_Iterator *it)
321{
322 return it->handle;
323}
324
325static 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
335static 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
433static HANDLE
434_eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
435{
436 return it->handle;
437}
438
439static 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
449static 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
464static 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
472static unsigned int
473_eina_file_map_key_length(const void *key __UNUSED__)
474{
475 return sizeof (unsigned long int) * 2;
476}
477
478static 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
486static 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
493static 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
573Eina_Bool
574eina_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
598Eina_Bool
599eina_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
626EAPI char *
627eina_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
665EAPI Eina_Bool
666eina_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
730EAPI Eina_Array *
731eina_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
763EAPI Eina_Iterator *
764eina_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
815EAPI Eina_Iterator *
816eina_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
874EAPI Eina_Iterator *
875eina_file_stat_ls(const char *dir)
876{
877 return eina_file_direct_ls(dir);
878}
879
880EAPI Eina_File *
881eina_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
990EAPI void
991eina_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
1008EAPI size_t
1009eina_file_size_get(Eina_File *file)
1010{
1011 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1012 return file->length;
1013}
1014
1015EAPI time_t
1016eina_file_mtime_get(Eina_File *file)
1017{
1018 EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
1019 return file->mtime;
1020}
1021
1022EAPI const char *
1023eina_file_filename_get(Eina_File *file)
1024{
1025 EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
1026 return file->filename;
1027}
1028
1029EAPI Eina_Iterator *eina_file_xattr_get(Eina_File *file __UNUSED__)
1030{
1031 return NULL;
1032}
1033
1034EAPI Eina_Iterator *eina_file_xattr_value_get(Eina_File *file __UNUSED__)
1035{
1036 return NULL;
1037}
1038
1039EAPI void *
1040eina_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
1067EAPI void *
1068eina_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
1132EAPI void
1133eina_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
1171EAPI int
1172eina_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}