Eina: DOS2UNIX eina_file_win32.c
authorcaro <caro>
Sun, 22 Jan 2012 08:57:50 +0000 (08:57 +0000)
committercaro <caro@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Sun, 22 Jan 2012 08:57:50 +0000 (08:57 +0000)
git-svn-id: http://svn.enlightenment.org/svn/e/trunk/eina@67445 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

src/lib/eina_file_win32.c

index 47de11a..54d3a10 100644 (file)
-/* EINA - EFL data type library\r
- * Copyright (C) 2010 Vincent Torri\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library;\r
- * if not, see <http://www.gnu.org/licenses/>.\r
- */\r
-\r
-#ifdef HAVE_CONFIG_H\r
-# include "config.h"\r
-#endif\r
-\r
-#ifdef HAVE_ALLOCA_H\r
-# include <alloca.h>\r
-#elif defined __GNUC__\r
-# define alloca __builtin_alloca\r
-#elif defined _AIX\r
-# define alloca __alloca\r
-#elif defined _MSC_VER\r
-# include <malloc.h>\r
-# define alloca _alloca\r
-#else\r
-# include <stddef.h>\r
-# ifdef  __cplusplus\r
-extern "C"\r
-# endif\r
-void *alloca (size_t);\r
-#endif\r
-\r
-#define WIN32_LEAN_AND_MEAN\r
-#include <windows.h>\r
-#undef WIN32_LEAN_AND_MEAN\r
-\r
-#include <Evil.h>\r
-\r
-#include "eina_config.h"\r
-#include "eina_private.h"\r
-\r
-/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */\r
-#include "eina_safety_checks.h"\r
-#include "eina_file.h"\r
-#include "eina_stringshare.h"\r
-#include "eina_hash.h"\r
-#include "eina_list.h"\r
-#include "eina_lock.h"\r
-#include "eina_log.h"\r
-\r
-/*============================================================================*\r
- *                                  Local                                     *\r
- *============================================================================*/\r
-\r
-/**\r
- * @cond LOCAL\r
- */\r
-\r
-#ifndef EINA_LOG_COLOR_DEFAULT\r
-#define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN\r
-#endif\r
-\r
-#ifdef ERR\r
-#undef ERR\r
-#endif\r
-#define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__)\r
-\r
-#ifdef WRN\r
-#undef WRN\r
-#endif\r
-#define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__)\r
-\r
-#ifdef DBG\r
-#undef DBG\r
-#endif\r
-#define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__)\r
-\r
-#ifdef MAP_FAILED\r
-# undef MAP_FAILED\r
-#endif\r
-#define MAP_FAILED ((void *)-1)\r
-\r
-typedef struct _Eina_File_Iterator        Eina_File_Iterator;\r
-typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;\r
-typedef struct _Eina_File_Map             Eina_File_Map;\r
-\r
-struct _Eina_File_Iterator\r
-{\r
-   Eina_Iterator   iterator;\r
-\r
-   WIN32_FIND_DATA data;\r
-   HANDLE          handle;\r
-   size_t          length;\r
-   Eina_Bool       is_last : 1;\r
-\r
-   char            dir[1];\r
-};\r
-\r
-struct _Eina_File_Direct_Iterator\r
-{\r
-   Eina_Iterator         iterator;\r
-\r
-   WIN32_FIND_DATA       data;\r
-   HANDLE                handle;\r
-   size_t                length;\r
-   Eina_Bool             is_last : 1;\r
-\r
-   Eina_File_Direct_Info info;\r
-\r
-   char                  dir[1];\r
-};\r
-\r
-struct _Eina_File\r
-{\r
-   const char *filename;\r
-\r
-   Eina_Hash *map;\r
-   Eina_Hash *rmap;\r
-   void *global_map;\r
-\r
-   Eina_Lock lock;\r
-\r
-   ULONGLONG length;\r
-   ULONGLONG mtime;\r
-\r
-   int refcount;\r
-   int global_refcount;\r
-\r
-   HANDLE handle;\r
-   HANDLE fm;\r
-\r
-   Eina_Bool shared : 1;\r
-   Eina_Bool delete_me : 1;\r
-};\r
-\r
-struct _Eina_File_Map\r
-{\r
-   void *map;\r
-\r
-   unsigned long int offset;\r
-   unsigned long int length;\r
-\r
-   int refcount;\r
-};\r
-\r
-static Eina_Hash *_eina_file_cache = NULL;\r
-static Eina_Lock _eina_file_lock_cache;\r
-\r
-static int _eina_file_log_dom = -1;\r
-\r
-static void\r
-_eina_file_win32_backslash_change(char *dir)\r
-{\r
-   char *tmp;\r
-\r
-   tmp = dir;\r
-   while (*tmp)\r
-     {\r
-        if (*tmp == '/') *tmp = '\\';\r
-        tmp++;\r
-     }\r
-}\r
-\r
-static Eina_Bool\r
-_eina_file_win32_is_dir(const char *dir)\r
-{\r
-#ifdef UNICODE\r
-   wchar_t *wdir = NULL;\r
-#endif\r
-   DWORD    attr;\r
-\r
-   /* check if it's a directory */\r
-#ifdef UNICODE\r
-   wdir = evil_char_to_wchar(dir);\r
-   if (!wdir)\r
-     return EINA_FALSE;\r
-\r
-   attr = GetFileAttributes(wdir);\r
-   free(wdir);\r
-#else\r
-   attr = GetFileAttributes(dir);\r
-#endif\r
-\r
-   if (attr == 0xFFFFFFFF)\r
-     return EINA_FALSE;\r
-\r
-   if (!(attr & FILE_ATTRIBUTE_DIRECTORY))\r
-     return EINA_FALSE;\r
-\r
-   return EINA_TRUE;\r
-}\r
-\r
-static char *\r
-_eina_file_win32_dir_new(const char *dir)\r
-{\r
-   char *new_dir;\r
-   size_t length;\r
-\r
-   length = strlen(dir);\r
-\r
-   new_dir = (char *)malloc(sizeof(char) * length + 5);\r
-   if (!new_dir)\r
-     return NULL;\r
-\r
-   memcpy(new_dir, dir, length);\r
-   memcpy(new_dir + length, "\\*.*", 5);\r
-   _eina_file_win32_backslash_change(new_dir);\r
-\r
-   return new_dir;\r
-}\r
-\r
-static HANDLE\r
-_eina_file_win32_first_file(const char *dir, WIN32_FIND_DATA *fd)\r
-{\r
-  HANDLE h;\r
-#ifdef UNICODE\r
-   wchar_t *wdir = NULL;\r
-\r
-   wdir = evil_char_to_wchar(dir);\r
-   if (!wdir)\r
-     return NULL;\r
-\r
-   h = FindFirstFile(wdir, fd);\r
-   free(wdir);\r
-#else\r
-   h = FindFirstFile(dir, fd);\r
-#endif\r
-\r
-   if (!h)\r
-     return NULL;\r
-\r
-   while ((fd->cFileName[0] == '.') &&\r
-          ((fd->cFileName[1] == '\0') ||\r
-           ((fd->cFileName[1] == '.') && (fd->cFileName[2] == '\0'))))\r
-     {\r
-        if (!FindNextFile(h, fd))\r
-          return NULL;\r
-     }\r
-\r
-   return h;\r
-}\r
-\r
-static Eina_Bool\r
-_eina_file_win32_ls_iterator_next(Eina_File_Iterator *it, void **data)\r
-{\r
-#ifdef UNICODE\r
-   wchar_t  *old_name;\r
-#else\r
-   char     *old_name;\r
-#endif\r
-   char     *name;\r
-   char     *cname;\r
-   size_t    length;\r
-   Eina_Bool is_last;\r
-   Eina_Bool res = EINA_TRUE;\r
-\r
-   if (it->handle == INVALID_HANDLE_VALUE)\r
-     return EINA_FALSE;\r
-\r
-   is_last = it->is_last;\r
-#ifdef UNICODE\r
-   old_name = _wcsdup(it->data.cFileName);\r
-#else\r
-   old_name = _strdup(it->data.cFileName);\r
-#endif\r
-   if (!old_name)\r
-     return EINA_FALSE;\r
-\r
-   do {\r
-      if (!FindNextFile(it->handle, &it->data))\r
-        {\r
-           if (GetLastError() == ERROR_NO_MORE_FILES)\r
-             it->is_last = EINA_TRUE;\r
-           else\r
-             res = EINA_FALSE;\r
-        }\r
-   } while ((it->data.cFileName[0] == '.') &&\r
-            ((it->data.cFileName[1] == '\0') ||\r
-             ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */\r
-\r
-#ifdef UNICODE\r
-   cname = evil_wchar_to_char(old_name);\r
-   if (!cname)\r
-     return EINA_FALSE;\r
-#else\r
-     cname = old_name;\r
-#endif\r
-\r
-   length = strlen(cname);\r
-   name = alloca(length + 2 + it->length);\r
-\r
-   memcpy(name,                  it->dir, it->length);\r
-   memcpy(name + it->length,     "\\",    1);\r
-   memcpy(name + it->length + 1, cname,   length + 1);\r
-\r
-   *data = (char *)eina_stringshare_add(name);\r
-\r
-#ifdef UNICODE\r
-   free(cname);\r
-#endif\r
-   free(old_name);\r
-\r
-   if (is_last)\r
-     res = EINA_FALSE;\r
-\r
-   return res;\r
-}\r
-\r
-static HANDLE\r
-_eina_file_win32_ls_iterator_container(Eina_File_Iterator *it)\r
-{\r
-   return it->handle;\r
-}\r
-\r
-static void\r
-_eina_file_win32_ls_iterator_free(Eina_File_Iterator *it)\r
-{\r
-   if (it->handle != INVALID_HANDLE_VALUE)\r
-     FindClose(it->handle);\r
-\r
-   EINA_MAGIC_SET(&it->iterator, 0);\r
-   free(it);\r
-}\r
-\r
-static Eina_Bool\r
-_eina_file_win32_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)\r
-{\r
-#ifdef UNICODE\r
-   wchar_t  *old_name;\r
-#else\r
-   char     *old_name;\r
-#endif\r
-   char     *cname;\r
-   size_t    length;\r
-   DWORD     attr;\r
-   Eina_Bool is_last;\r
-   Eina_Bool res = EINA_TRUE;\r
-\r
-   if (it->handle == INVALID_HANDLE_VALUE)\r
-     return EINA_FALSE;\r
-\r
-   attr = it->data.dwFileAttributes;\r
-   is_last = it->is_last;\r
-#ifdef UNICODE\r
-   old_name = _wcsdup(it->data.cFileName);\r
-#else\r
-   old_name = _strdup(it->data.cFileName);\r
-#endif\r
-   if (!old_name)\r
-     return EINA_FALSE;\r
-\r
-   do {\r
-      if (!FindNextFile(it->handle, &it->data))\r
-        {\r
-           if (GetLastError() == ERROR_NO_MORE_FILES)\r
-             it->is_last = EINA_TRUE;\r
-           else\r
-             res = EINA_FALSE;\r
-        }\r
-\r
-#ifdef UNICODE\r
-     length = wcslen(old_name);\r
-#else\r
-     length = strlen(old_name);\r
-#endif\r
-     if (it->info.name_start + length + 1 >= PATH_MAX)\r
-       {\r
-          free(old_name);\r
-#ifdef UNICODE\r
-          old_name = _wcsdup(it->data.cFileName);\r
-#else\r
-          old_name = _strdup(it->data.cFileName);\r
-#endif\r
-          continue;\r
-       }\r
-\r
-   } while ((it->data.cFileName[0] == '.') &&\r
-            ((it->data.cFileName[1] == '\0') ||\r
-             ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */\r
-\r
-#ifdef UNICODE\r
-   cname = evil_wchar_to_char(old_name);\r
-   if (!cname)\r
-     return EINA_FALSE;\r
-#else\r
-     cname = old_name;\r
-#endif\r
-\r
-   memcpy(it->info.path + it->info.name_start, cname, length);\r
-   it->info.name_length = length;\r
-   it->info.path_length = it->info.name_start + length;\r
-   it->info.path[it->info.path_length] = '\0';\r
-\r
-   if (attr & FILE_ATTRIBUTE_DIRECTORY)\r
-     it->info.type = EINA_FILE_DIR;\r
-   else if (attr & FILE_ATTRIBUTE_REPARSE_POINT)\r
-     it->info.type = EINA_FILE_LNK;\r
-   else if (attr & (FILE_ATTRIBUTE_ARCHIVE |\r
-                    FILE_ATTRIBUTE_COMPRESSED |\r
-                    FILE_ATTRIBUTE_COMPRESSED |\r
-                    FILE_ATTRIBUTE_HIDDEN |\r
-                    FILE_ATTRIBUTE_NORMAL |\r
-                    FILE_ATTRIBUTE_SPARSE_FILE |\r
-                    FILE_ATTRIBUTE_TEMPORARY))\r
-     it->info.type = EINA_FILE_REG;\r
-   else\r
-     it->info.type = EINA_FILE_UNKNOWN;\r
-\r
-   *data = &it->info;\r
-\r
-#ifdef UNICODE\r
-   free(cname);\r
-#endif\r
-\r
-   free(old_name);\r
-\r
-   if (is_last)\r
-     res = EINA_FALSE;\r
-\r
-   return res;\r
-}\r
-\r
-static HANDLE\r
-_eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)\r
-{\r
-   return it->handle;\r
-}\r
-\r
-static void\r
-_eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)\r
-{\r
-   if (it->handle != INVALID_HANDLE_VALUE)\r
-     FindClose(it->handle);\r
-\r
-   EINA_MAGIC_SET(&it->iterator, 0);\r
-   free(it);\r
-}\r
-\r
-static void\r
-_eina_file_real_close(Eina_File *file)\r
-{\r
-   eina_hash_free(file->rmap);\r
-   eina_hash_free(file->map);\r
-\r
-   if (file->global_map != MAP_FAILED)\r
-     UnmapViewOfFile(file->global_map);\r
-\r
-   CloseHandle(file->fm);\r
-   CloseHandle(file->handle);\r
-\r
-   eina_stringshare_del(file->filename);\r
-\r
-   free(file);\r
-}\r
-\r
-static void\r
-_eina_file_map_close(Eina_File_Map *map)\r
-{\r
-   if (map->map != MAP_FAILED)\r
-     UnmapViewOfFile(map->map);\r
-   free(map);\r
-}\r
-\r
-static unsigned int\r
-_eina_file_map_key_length(const void *key __UNUSED__)\r
-{\r
-   return sizeof (unsigned long int) * 2;\r
-}\r
-\r
-static int\r
-_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__,\r
-                       const unsigned long int *key2, int key2_length __UNUSED__)\r
-{\r
-   if (key1[0] - key2[0] == 0) return key1[1] - key2[1];\r
-   return key1[0] - key2[0];\r
-}\r
-\r
-static int\r
-_eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__)\r
-{\r
-   return eina_hash_int64(&key[0], sizeof (unsigned long int))\r
-     ^ eina_hash_int64(&key[1], sizeof (unsigned long int));\r
-}\r
-\r
-static char *\r
-_eina_file_win32_escape(const char *path, size_t *length)\r
-{\r
-   char *result = strdup(path ? path : "");\r
-   char *p = result;\r
-   char *q = result;\r
-   size_t len;\r
-\r
-   if (!result)\r
-     return NULL;\r
-\r
-   if (length) len = *length;\r
-   else len = strlen(result);\r
-\r
-   while ((p = strchr(p, '/')))\r
-     {\r
-        // remove double `/'\r
-        if (p[1] == '/')\r
-          {\r
-             memmove(p, p + 1, --len - (p - result));\r
-             result[len] = '\0';\r
-          }\r
-        else\r
-          if (p[1] == '.'\r
-              && p[2] == '.')\r
-            {\r
-               // remove `/../'\r
-               if (p[3] == '/')\r
-                 {\r
-                    char tmp;\r
-\r
-                    len -= p + 3 - q;\r
-                    memmove(q, p + 3, len - (q - result));\r
-                    result[len] = '\0';\r
-                    p = q;\r
-\r
-                    /* Update q correctly. */\r
-                    tmp = *p;\r
-                    *p = '\0';\r
-                    q = strrchr(result, '/');\r
-                    if (!q) q = result;\r
-                    *p = tmp;\r
-                 }\r
-               else\r
-                 // remove '/..$'\r
-                 if (p[3] == '\0')\r
-                   {\r
-                      len -= p + 2 - q;\r
-                      result[len] = '\0';\r
-                      q = p;\r
-                      ++p;\r
-                   }\r
-                 else\r
-                   {\r
-                      q = p;\r
-                      ++p;\r
-                   }\r
-            }\r
-          else\r
-            {\r
-               q = p;\r
-               ++p;\r
-            }\r
-     }\r
-\r
-   if (length)\r
-     *length = len;\r
-\r
-   return result;\r
-}\r
-\r
-\r
-/**\r
- * @endcond\r
- */\r
-\r
-/*============================================================================*\r
- *                                 Global                                     *\r
- *============================================================================*/\r
-\r
-Eina_Bool\r
-eina_file_init(void)\r
-{\r
-   _eina_file_log_dom = eina_log_domain_register("eina_file",\r
-                                                 EINA_LOG_COLOR_DEFAULT);\r
-   if (_eina_file_log_dom < 0)\r
-     {\r
-        EINA_LOG_ERR("Could not register log domain: eina_file");\r
-        return EINA_FALSE;\r
-     }\r
-\r
-   _eina_file_cache = eina_hash_string_djb2_new(NULL);\r
-   if (!_eina_file_cache)\r
-     {\r
-        ERR("Could not create cache.");\r
-        eina_log_domain_unregister(_eina_file_log_dom);\r
-        _eina_file_log_dom = -1;\r
-        return EINA_FALSE;\r
-     }\r
-\r
-   eina_lock_new(&_eina_file_lock_cache);\r
-\r
-   return EINA_TRUE;\r
-}\r
-\r
-Eina_Bool\r
-eina_file_shutdown(void)\r
-{\r
-   if (eina_hash_population(_eina_file_cache) > 0)\r
-     {\r
-        Eina_Iterator *it;\r
-        const char *key;\r
-\r
-        it = eina_hash_iterator_key_new(_eina_file_cache);\r
-        EINA_ITERATOR_FOREACH(it, key)\r
-          ERR("File [%s] still open !", key);\r
-        eina_iterator_free(it);\r
-     }\r
-\r
-   eina_hash_free(_eina_file_cache);\r
-\r
-   eina_lock_free(&_eina_file_lock_cache);\r
-\r
-   eina_log_domain_unregister(_eina_file_log_dom);\r
-   _eina_file_log_dom = -1;\r
-   return EINA_TRUE;\r
-}\r
-\r
-/*============================================================================*\r
- *                                   API                                      *\r
- *============================================================================*/\r
-\r
-\r
-EAPI char *\r
-eina_file_path_sanitize(const char *path)\r
-{\r
-   char *result = NULL;\r
-   size_t len;\r
-\r
-   if (!path) return NULL;\r
-\r
-   len = strlen(path);\r
-   if (len < 3) return NULL;\r
-\r
-   if (!evil_path_is_absolute(path))\r
-     {\r
-        DWORD l;\r
-\r
-        l = GetCurrentDirectory(0, NULL);\r
-        if (l > 0)\r
-          {\r
-             char *cwd;\r
-             DWORD l2;\r
-\r
-             cwd = alloca(sizeof(char) * (l + 1));\r
-             l2 = GetCurrentDirectory(l + 1, cwd);\r
-             if (l2 == l)\r
-               {\r
-                  char *tmp;\r
-\r
-                  len += l + 2;\r
-                  tmp = alloca(sizeof (char) * len);\r
-                  snprintf(tmp, len, "%s/%s", cwd, path);\r
-                  tmp[len - 1] = '\0';\r
-                  result = tmp;\r
-               }\r
-          }\r
-     }\r
-\r
-   return _eina_file_win32_escape(result ? result : path, &len);\r
-}\r
-\r
-EAPI Eina_Bool\r
-eina_file_dir_list(const char *dir,\r
-                   Eina_Bool recursive,\r
-                   Eina_File_Dir_List_Cb cb,\r
-                   void *data)\r
-{\r
-   WIN32_FIND_DATA file;\r
-   HANDLE h;\r
-   char *new_dir;\r
-\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(cb,  EINA_FALSE);\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);\r
-   EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);\r
-\r
-   if (!_eina_file_win32_is_dir(dir))\r
-     return EINA_FALSE;\r
-\r
-   new_dir = _eina_file_win32_dir_new(dir);\r
-   if (!new_dir)\r
-      return EINA_FALSE;\r
-\r
-   h = _eina_file_win32_first_file(new_dir, &file);\r
-\r
-   if (h == INVALID_HANDLE_VALUE)\r
-      return EINA_FALSE;\r
-\r
-   do\r
-     {\r
-        char *filename;\r
-\r
-# ifdef UNICODE\r
-        filename = evil_wchar_to_char(file.cFileName);\r
-# else\r
-        filename = file.cFileName;\r
-# endif /* ! UNICODE */\r
-        if (!strcmp(filename, ".") || !strcmp(filename, ".."))\r
-           continue;\r
-\r
-        cb(filename, dir, data);\r
-\r
-        if (recursive == EINA_TRUE)\r
-          {\r
-             char *path;\r
-\r
-             path = alloca(strlen(dir) + strlen(filename) + 2);\r
-             strcpy(path, dir);\r
-             strcat(path, "/");\r
-             strcat(path, filename);\r
-\r
-             if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))\r
-                continue;\r
-\r
-             eina_file_dir_list(path, recursive, cb, data);\r
-          }\r
-\r
-# ifdef UNICODE\r
-        free(filename);\r
-# endif /* UNICODE */\r
-\r
-     } while (FindNextFile(h, &file));\r
-   FindClose(h);\r
-\r
-   return EINA_TRUE;\r
-}\r
-\r
-EAPI Eina_Array *\r
-eina_file_split(char *path)\r
-{\r
-   Eina_Array *ea;\r
-   char *current;\r
-   size_t length;\r
-\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);\r
-\r
-   ea = eina_array_new(16);\r
-\r
-   if (!ea)\r
-      return NULL;\r
-\r
-   for (current = strchr(path, '\\');\r
-        current;\r
-        path = current + 1, current = strchr(path, '\\'))\r
-     {\r
-        length = current - path;\r
-\r
-        if (length <= 0)\r
-           continue;\r
-\r
-        eina_array_push(ea, path);\r
-        *current = '\0';\r
-     }\r
-\r
-   if (*path != '\0')\r
-        eina_array_push(ea, path);\r
-\r
-   return ea;\r
-}\r
-\r
-EAPI Eina_Iterator *\r
-eina_file_ls(const char *dir)\r
-{\r
-   Eina_File_Iterator *it;\r
-   char               *new_dir;\r
-   size_t              length;\r
-\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);\r
-\r
-   if (!dir || !*dir)\r
-      return NULL;\r
-\r
-   if (!_eina_file_win32_is_dir(dir))\r
-     return NULL;\r
-\r
-   length = strlen(dir);\r
-\r
-   it = calloc(1, sizeof (Eina_File_Iterator) + length);\r
-   if (!it)\r
-      return NULL;\r
-\r
-   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);\r
-\r
-   new_dir = _eina_file_win32_dir_new(dir);\r
-   if (!new_dir)\r
-      goto free_it;\r
-\r
-   it->handle = _eina_file_win32_first_file(new_dir, &it->data);\r
-   free(new_dir);\r
-   if (it->handle == INVALID_HANDLE_VALUE)\r
-     goto free_it;\r
-\r
-   memcpy(it->dir, dir, length + 1);\r
-   if (dir[length - 1] != '\\')\r
-      it->length = length;\r
-   else\r
-      it->length = length - 1;\r
-   _eina_file_win32_backslash_change(it->dir);\r
-\r
-   it->iterator.version = EINA_ITERATOR_VERSION;\r
-   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_ls_iterator_next);\r
-   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_ls_iterator_container);\r
-   it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_ls_iterator_free);\r
-\r
-   return &it->iterator;\r
-\r
- free_it:\r
-   free(it);\r
-\r
-   return NULL;\r
-}\r
-\r
-EAPI Eina_Iterator *\r
-eina_file_direct_ls(const char *dir)\r
-{\r
-   Eina_File_Direct_Iterator *it;\r
-   char                      *new_dir;\r
-   size_t                     length;\r
-\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);\r
-\r
-   if (!dir || !*dir)\r
-      return NULL;\r
-\r
-   length = strlen(dir);\r
-\r
-   if (length + 12 + 2 >= MAX_PATH)\r
-      return NULL;\r
-\r
-   it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);\r
-   if (!it)\r
-      return NULL;\r
-\r
-   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);\r
-\r
-   new_dir = _eina_file_win32_dir_new(dir);\r
-   if (!new_dir)\r
-      goto free_it;\r
-\r
-   it->handle = _eina_file_win32_first_file(new_dir, &it->data);\r
-   free(new_dir);\r
-   if (it->handle == INVALID_HANDLE_VALUE)\r
-     goto free_it;\r
-\r
-   memcpy(it->dir, dir, length + 1);\r
-   it->length = length;\r
-   _eina_file_win32_backslash_change(it->dir);\r
-\r
-   memcpy(it->info.path, dir, length);\r
-   if (dir[length - 1] == '\\')\r
-      it->info.name_start = length;\r
-   else\r
-     {\r
-        it->info.path[length] = '\\';\r
-        it->info.name_start = length + 1;\r
-     }\r
-   _eina_file_win32_backslash_change(it->info.path);\r
-\r
-   it->iterator.version = EINA_ITERATOR_VERSION;\r
-   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_direct_ls_iterator_next);\r
-   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_direct_ls_iterator_container);\r
-   it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_direct_ls_iterator_free);\r
-\r
-   return &it->iterator;\r
-\r
- free_it:\r
-   free(it);\r
-\r
-   return NULL;\r
-}\r
-\r
-EAPI Eina_Iterator *\r
-eina_file_stat_ls(const char *dir)\r
-{\r
-   return eina_file_direct_ls(dir);\r
-}\r
-\r
-EAPI Eina_File *\r
-eina_file_open(const char *path, Eina_Bool shared)\r
-{\r
-   Eina_File *file;\r
-   Eina_File *n;\r
-   char *filename;\r
-   HANDLE handle;\r
-   HANDLE fm;\r
-   WIN32_FILE_ATTRIBUTE_DATA fad;\r
-   ULARGE_INTEGER length;\r
-   ULARGE_INTEGER mtime;\r
-\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);\r
-\r
-   filename = eina_file_path_sanitize(path);\r
-   if (!filename) return NULL;\r
-\r
-   /* FIXME: how to emulate shm_open ? Just OpenFileMapping ? */\r
-#if 0\r
-   if (shared)\r
-     handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,\r
-                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,\r
-                         NULL);\r
-   else\r
-#endif\r
-     handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,\r
-                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,\r
-                         NULL);\r
-\r
-   if (handle == INVALID_HANDLE_VALUE)\r
-     return NULL;\r
-\r
-   fm = CreateFileMapping(handle, NULL, PAGE_READONLY, 0, 0, NULL);\r
-   if (!fm)\r
-     goto close_handle;\r
-\r
-   if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad))\r
-     goto close_fm;\r
-\r
-   length.u.LowPart = fad.nFileSizeLow;\r
-   length.u.HighPart = fad.nFileSizeHigh;\r
-   mtime.u.LowPart = fad.ftLastWriteTime.dwLowDateTime;\r
-   mtime.u.HighPart = fad.ftLastWriteTime.dwHighDateTime;\r
-\r
-   eina_lock_take(&_eina_file_lock_cache);\r
-\r
-   file = eina_hash_find(_eina_file_cache, filename);\r
-   if (file &&\r
-       (file->mtime == mtime.QuadPart && file->length == length.QuadPart))\r
-     {\r
-        file->delete_me = EINA_TRUE;\r
-        eina_hash_del(_eina_file_cache, file->filename, file);\r
-        _eina_file_real_close(file);\r
-        file = NULL;\r
-     }\r
-\r
-   if (!file)\r
-     {\r
-        n = malloc(sizeof (Eina_File) + strlen(filename) + 1);\r
-        if (!n)\r
-          {\r
-             eina_lock_release(&_eina_file_lock_cache);\r
-             goto close_fm;\r
-          }\r
-\r
-        n->filename = (char*) (n + 1);\r
-        strcpy((char*) n->filename, filename);\r
-        n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length),\r
-                               EINA_KEY_CMP(_eina_file_map_key_cmp),\r
-                               EINA_KEY_HASH(_eina_file_map_key_hash),\r
-                               EINA_FREE_CB(_eina_file_map_close),\r
-                               3);\r
-        n->rmap = eina_hash_pointer_new(NULL);\r
-        n->global_map = MAP_FAILED;\r
-        n->global_refcount = 0;\r
-        n->length = length.QuadPart;\r
-        n->mtime = mtime.QuadPart;\r
-        n->refcount = 0;\r
-        n->handle = handle;\r
-        n->fm = fm;\r
-        n->shared = shared;\r
-        n->delete_me = EINA_FALSE;\r
-        eina_lock_new(&n->lock);\r
-        eina_hash_direct_add(_eina_file_cache, n->filename, n);\r
-     }\r
-   else\r
-     {\r
-        CloseHandle(fm);\r
-        CloseHandle(handle);\r
-\r
-        n = file;\r
-     }\r
-   eina_lock_take(&n->lock);\r
-   n->refcount++;\r
-   eina_lock_release(&n->lock);\r
-\r
-   eina_lock_release(&_eina_file_lock_cache);\r
-\r
-   free(filename);\r
-\r
-   return n;\r
-\r
- close_fm:\r
-   CloseHandle(fm);\r
- close_handle:\r
-   CloseHandle(handle);\r
-\r
-   return NULL;\r
-}\r
-\r
-EAPI void\r
-eina_file_close(Eina_File *file)\r
-{\r
-   EINA_SAFETY_ON_NULL_RETURN(file);\r
-\r
-   eina_lock_take(&file->lock);\r
-   file->refcount--;\r
-   eina_lock_release(&file->lock);\r
-\r
-   if (file->refcount != 0) return ;\r
-   eina_lock_take(&_eina_file_lock_cache);\r
-\r
-   eina_hash_del(_eina_file_cache, file->filename, file);\r
-   _eina_file_real_close(file);\r
-   \r
-   eina_lock_release(&_eina_file_lock_cache);\r
-}\r
-\r
-EAPI size_t\r
-eina_file_size_get(Eina_File *file)\r
-{\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);\r
-   return file->length;\r
-}\r
-\r
-EAPI time_t\r
-eina_file_mtime_get(Eina_File *file)\r
-{\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);\r
-  return file->mtime;\r
-}\r
-\r
-EAPI const char *\r
-eina_file_filename_get(Eina_File *file)\r
-{\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);\r
-   return file->filename;\r
-}\r
-\r
-EAPI void *\r
-eina_file_map_all(Eina_File *file, Eina_File_Populate rule __UNUSED__)\r
-{\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);\r
-\r
-   eina_lock_take(&file->lock);\r
-   if (file->global_map == MAP_FAILED)\r
-     {\r
-        void  *data;\r
-\r
-        data = MapViewOfFile(file->fm, FILE_MAP_READ,\r
-                             0, 0, file->length);\r
-        if (!data)\r
-          file->global_map = MAP_FAILED;\r
-        else\r
-          file->global_map = data;\r
-     }\r
-\r
-   if (file->global_map != MAP_FAILED)\r
-     {\r
-        file->global_refcount++;\r
-        return file->global_map;\r
-     }\r
-\r
-   eina_lock_release(&file->lock);\r
-   return NULL;\r
-}\r
-\r
-EAPI void *\r
-eina_file_map_new(Eina_File *file, Eina_File_Populate rule,\r
-                  unsigned long int offset, unsigned long int length)\r
-{\r
-   Eina_File_Map *map;\r
-   unsigned long int key[2];\r
-\r
-   EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);\r
-\r
-   if (offset > file->length)\r
-     return NULL;\r
-   if (offset + length > file->length)\r
-     return NULL;\r
-\r
-   if (offset == 0 && length == file->length)\r
-     return eina_file_map_all(file, rule);\r
-\r
-   key[0] = offset;\r
-   key[1] = length;\r
-\r
-   eina_lock_take(&file->lock);\r
-\r
-   map = eina_hash_find(file->map, &key);\r
-   if (!map)\r
-     {\r
-        void  *data;\r
-\r
-        map = malloc(sizeof (Eina_File_Map));\r
-        if (!map) return NULL;\r
-\r
-        data = MapViewOfFile(file->fm, FILE_MAP_READ,\r
-                             offset & 0xffff0000,\r
-                             offset & 0x0000ffff,\r
-                             length);\r
-        if (!data)\r
-          map->map = MAP_FAILED;\r
-        else\r
-          map->map = data;\r
-\r
-        map->offset = offset;\r
-        map->length = length;\r
-        map->refcount = 0;\r
-\r
-        if (map->map == MAP_FAILED)\r
-          {\r
-             free(map);\r
-             return NULL;\r
-          }\r
-\r
-        eina_hash_add(file->map, &key, map);\r
-        eina_hash_direct_add(file->rmap, map->map, map);\r
-     }\r
-\r
-   map->refcount++;\r
-\r
-   eina_lock_release(&file->lock);\r
-\r
-   return map->map;\r
-}\r
-\r
-EAPI void\r
-eina_file_map_free(Eina_File *file, void *map)\r
-{\r
-   EINA_SAFETY_ON_NULL_RETURN(file);\r
-\r
-   eina_lock_take(&file->lock);\r
-\r
-   if (file->global_map == map)\r
-     {\r
-        file->global_refcount--;\r
-\r
-        if (file->global_refcount > 0) goto on_exit;\r
-\r
-        UnmapViewOfFile(file->global_map);\r
-        file->global_map = MAP_FAILED;\r
-     }\r
-   else\r
-     {\r
-        Eina_File_Map *em;\r
-        unsigned long int key[2];\r
-\r
-        em = eina_hash_find(file->rmap, &map);\r
-        if (!em) return ;\r
-\r
-        em->refcount--;\r
-\r
-        if (em->refcount > 0) goto on_exit;\r
-\r
-        key[0] = em->offset;\r
-        key[1] = em->length;\r
-\r
-        eina_hash_del(file->rmap, &map, em);\r
-        eina_hash_del(file->map, &key, em);\r
-     }\r
-\r
- on_exit:\r
-   eina_lock_release(&file->lock);\r
-}\r
+/* EINA - EFL data type library
+ * Copyright (C) 2010 Vincent Torri
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef HAVE_ALLOCA_H
+# include <alloca.h>
+#elif defined __GNUC__
+# define alloca __builtin_alloca
+#elif defined _AIX
+# define alloca __alloca
+#elif defined _MSC_VER
+# include <malloc.h>
+# define alloca _alloca
+#else
+# include <stddef.h>
+# ifdef  __cplusplus
+extern "C"
+# endif
+void *alloca (size_t);
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#undef WIN32_LEAN_AND_MEAN
+
+#include <Evil.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
+#include "eina_safety_checks.h"
+#include "eina_file.h"
+#include "eina_stringshare.h"
+#include "eina_hash.h"
+#include "eina_list.h"
+#include "eina_lock.h"
+#include "eina_log.h"
+
+/*============================================================================*
+ *                                  Local                                     *
+ *============================================================================*/
+
+/**
+ * @cond LOCAL
+ */
+
+#ifndef EINA_LOG_COLOR_DEFAULT
+#define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN
+#endif
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_file_log_dom, __VA_ARGS__)
+
+#ifdef WRN
+#undef WRN
+#endif
+#define WRN(...) EINA_LOG_DOM_WARN(_eina_file_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__)
+
+#ifdef MAP_FAILED
+# undef MAP_FAILED
+#endif
+#define MAP_FAILED ((void *)-1)
+
+typedef struct _Eina_File_Iterator        Eina_File_Iterator;
+typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
+typedef struct _Eina_File_Map             Eina_File_Map;
+
+struct _Eina_File_Iterator
+{
+   Eina_Iterator   iterator;
+
+   WIN32_FIND_DATA data;
+   HANDLE          handle;
+   size_t          length;
+   Eina_Bool       is_last : 1;
+
+   char            dir[1];
+};
+
+struct _Eina_File_Direct_Iterator
+{
+   Eina_Iterator         iterator;
+
+   WIN32_FIND_DATA       data;
+   HANDLE                handle;
+   size_t                length;
+   Eina_Bool             is_last : 1;
+
+   Eina_File_Direct_Info info;
+
+   char                  dir[1];
+};
+
+struct _Eina_File
+{
+   const char *filename;
+
+   Eina_Hash *map;
+   Eina_Hash *rmap;
+   void *global_map;
+
+   Eina_Lock lock;
+
+   ULONGLONG length;
+   ULONGLONG mtime;
+
+   int refcount;
+   int global_refcount;
+
+   HANDLE handle;
+   HANDLE fm;
+
+   Eina_Bool shared : 1;
+   Eina_Bool delete_me : 1;
+};
+
+struct _Eina_File_Map
+{
+   void *map;
+
+   unsigned long int offset;
+   unsigned long int length;
+
+   int refcount;
+};
+
+static Eina_Hash *_eina_file_cache = NULL;
+static Eina_Lock _eina_file_lock_cache;
+
+static int _eina_file_log_dom = -1;
+
+static void
+_eina_file_win32_backslash_change(char *dir)
+{
+   char *tmp;
+
+   tmp = dir;
+   while (*tmp)
+     {
+        if (*tmp == '/') *tmp = '\\';
+        tmp++;
+     }
+}
+
+static Eina_Bool
+_eina_file_win32_is_dir(const char *dir)
+{
+#ifdef UNICODE
+   wchar_t *wdir = NULL;
+#endif
+   DWORD    attr;
+
+   /* check if it's a directory */
+#ifdef UNICODE
+   wdir = evil_char_to_wchar(dir);
+   if (!wdir)
+     return EINA_FALSE;
+
+   attr = GetFileAttributes(wdir);
+   free(wdir);
+#else
+   attr = GetFileAttributes(dir);
+#endif
+
+   if (attr == 0xFFFFFFFF)
+     return EINA_FALSE;
+
+   if (!(attr & FILE_ATTRIBUTE_DIRECTORY))
+     return EINA_FALSE;
+
+   return EINA_TRUE;
+}
+
+static char *
+_eina_file_win32_dir_new(const char *dir)
+{
+   char *new_dir;
+   size_t length;
+
+   length = strlen(dir);
+
+   new_dir = (char *)malloc(sizeof(char) * length + 5);
+   if (!new_dir)
+     return NULL;
+
+   memcpy(new_dir, dir, length);
+   memcpy(new_dir + length, "\\*.*", 5);
+   _eina_file_win32_backslash_change(new_dir);
+
+   return new_dir;
+}
+
+static HANDLE
+_eina_file_win32_first_file(const char *dir, WIN32_FIND_DATA *fd)
+{
+  HANDLE h;
+#ifdef UNICODE
+   wchar_t *wdir = NULL;
+
+   wdir = evil_char_to_wchar(dir);
+   if (!wdir)
+     return NULL;
+
+   h = FindFirstFile(wdir, fd);
+   free(wdir);
+#else
+   h = FindFirstFile(dir, fd);
+#endif
+
+   if (!h)
+     return NULL;
+
+   while ((fd->cFileName[0] == '.') &&
+          ((fd->cFileName[1] == '\0') ||
+           ((fd->cFileName[1] == '.') && (fd->cFileName[2] == '\0'))))
+     {
+        if (!FindNextFile(h, fd))
+          return NULL;
+     }
+
+   return h;
+}
+
+static Eina_Bool
+_eina_file_win32_ls_iterator_next(Eina_File_Iterator *it, void **data)
+{
+#ifdef UNICODE
+   wchar_t  *old_name;
+#else
+   char     *old_name;
+#endif
+   char     *name;
+   char     *cname;
+   size_t    length;
+   Eina_Bool is_last;
+   Eina_Bool res = EINA_TRUE;
+
+   if (it->handle == INVALID_HANDLE_VALUE)
+     return EINA_FALSE;
+
+   is_last = it->is_last;
+#ifdef UNICODE
+   old_name = _wcsdup(it->data.cFileName);
+#else
+   old_name = _strdup(it->data.cFileName);
+#endif
+   if (!old_name)
+     return EINA_FALSE;
+
+   do {
+      if (!FindNextFile(it->handle, &it->data))
+        {
+           if (GetLastError() == ERROR_NO_MORE_FILES)
+             it->is_last = EINA_TRUE;
+           else
+             res = EINA_FALSE;
+        }
+   } while ((it->data.cFileName[0] == '.') &&
+            ((it->data.cFileName[1] == '\0') ||
+             ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */
+
+#ifdef UNICODE
+   cname = evil_wchar_to_char(old_name);
+   if (!cname)
+     return EINA_FALSE;
+#else
+     cname = old_name;
+#endif
+
+   length = strlen(cname);
+   name = alloca(length + 2 + it->length);
+
+   memcpy(name,                  it->dir, it->length);
+   memcpy(name + it->length,     "\\",    1);
+   memcpy(name + it->length + 1, cname,   length + 1);
+
+   *data = (char *)eina_stringshare_add(name);
+
+#ifdef UNICODE
+   free(cname);
+#endif
+   free(old_name);
+
+   if (is_last)
+     res = EINA_FALSE;
+
+   return res;
+}
+
+static HANDLE
+_eina_file_win32_ls_iterator_container(Eina_File_Iterator *it)
+{
+   return it->handle;
+}
+
+static void
+_eina_file_win32_ls_iterator_free(Eina_File_Iterator *it)
+{
+   if (it->handle != INVALID_HANDLE_VALUE)
+     FindClose(it->handle);
+
+   EINA_MAGIC_SET(&it->iterator, 0);
+   free(it);
+}
+
+static Eina_Bool
+_eina_file_win32_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
+{
+#ifdef UNICODE
+   wchar_t  *old_name;
+#else
+   char     *old_name;
+#endif
+   char     *cname;
+   size_t    length;
+   DWORD     attr;
+   Eina_Bool is_last;
+   Eina_Bool res = EINA_TRUE;
+
+   if (it->handle == INVALID_HANDLE_VALUE)
+     return EINA_FALSE;
+
+   attr = it->data.dwFileAttributes;
+   is_last = it->is_last;
+#ifdef UNICODE
+   old_name = _wcsdup(it->data.cFileName);
+#else
+   old_name = _strdup(it->data.cFileName);
+#endif
+   if (!old_name)
+     return EINA_FALSE;
+
+   do {
+      if (!FindNextFile(it->handle, &it->data))
+        {
+           if (GetLastError() == ERROR_NO_MORE_FILES)
+             it->is_last = EINA_TRUE;
+           else
+             res = EINA_FALSE;
+        }
+
+#ifdef UNICODE
+     length = wcslen(old_name);
+#else
+     length = strlen(old_name);
+#endif
+     if (it->info.name_start + length + 1 >= PATH_MAX)
+       {
+          free(old_name);
+#ifdef UNICODE
+          old_name = _wcsdup(it->data.cFileName);
+#else
+          old_name = _strdup(it->data.cFileName);
+#endif
+          continue;
+       }
+
+   } while ((it->data.cFileName[0] == '.') &&
+            ((it->data.cFileName[1] == '\0') ||
+             ((it->data.cFileName[1] == '.') && (it->data.cFileName[2] == '\0')))); /* FIXME: what about UNICODE ? */
+
+#ifdef UNICODE
+   cname = evil_wchar_to_char(old_name);
+   if (!cname)
+     return EINA_FALSE;
+#else
+     cname = old_name;
+#endif
+
+   memcpy(it->info.path + it->info.name_start, cname, length);
+   it->info.name_length = length;
+   it->info.path_length = it->info.name_start + length;
+   it->info.path[it->info.path_length] = '\0';
+
+   if (attr & FILE_ATTRIBUTE_DIRECTORY)
+     it->info.type = EINA_FILE_DIR;
+   else if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
+     it->info.type = EINA_FILE_LNK;
+   else if (attr & (FILE_ATTRIBUTE_ARCHIVE |
+                    FILE_ATTRIBUTE_COMPRESSED |
+                    FILE_ATTRIBUTE_COMPRESSED |
+                    FILE_ATTRIBUTE_HIDDEN |
+                    FILE_ATTRIBUTE_NORMAL |
+                    FILE_ATTRIBUTE_SPARSE_FILE |
+                    FILE_ATTRIBUTE_TEMPORARY))
+     it->info.type = EINA_FILE_REG;
+   else
+     it->info.type = EINA_FILE_UNKNOWN;
+
+   *data = &it->info;
+
+#ifdef UNICODE
+   free(cname);
+#endif
+
+   free(old_name);
+
+   if (is_last)
+     res = EINA_FALSE;
+
+   return res;
+}
+
+static HANDLE
+_eina_file_win32_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
+{
+   return it->handle;
+}
+
+static void
+_eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
+{
+   if (it->handle != INVALID_HANDLE_VALUE)
+     FindClose(it->handle);
+
+   EINA_MAGIC_SET(&it->iterator, 0);
+   free(it);
+}
+
+static void
+_eina_file_real_close(Eina_File *file)
+{
+   eina_hash_free(file->rmap);
+   eina_hash_free(file->map);
+
+   if (file->global_map != MAP_FAILED)
+     UnmapViewOfFile(file->global_map);
+
+   CloseHandle(file->fm);
+   CloseHandle(file->handle);
+
+   eina_stringshare_del(file->filename);
+
+   free(file);
+}
+
+static void
+_eina_file_map_close(Eina_File_Map *map)
+{
+   if (map->map != MAP_FAILED)
+     UnmapViewOfFile(map->map);
+   free(map);
+}
+
+static unsigned int
+_eina_file_map_key_length(const void *key __UNUSED__)
+{
+   return sizeof (unsigned long int) * 2;
+}
+
+static int
+_eina_file_map_key_cmp(const unsigned long int *key1, int key1_length __UNUSED__,
+                       const unsigned long int *key2, int key2_length __UNUSED__)
+{
+   if (key1[0] - key2[0] == 0) return key1[1] - key2[1];
+   return key1[0] - key2[0];
+}
+
+static int
+_eina_file_map_key_hash(const unsigned long int *key, int key_length __UNUSED__)
+{
+   return eina_hash_int64(&key[0], sizeof (unsigned long int))
+     ^ eina_hash_int64(&key[1], sizeof (unsigned long int));
+}
+
+static char *
+_eina_file_win32_escape(const char *path, size_t *length)
+{
+   char *result = strdup(path ? path : "");
+   char *p = result;
+   char *q = result;
+   size_t len;
+
+   if (!result)
+     return NULL;
+
+   if (length) len = *length;
+   else len = strlen(result);
+
+   while ((p = strchr(p, '/')))
+     {
+        // remove double `/'
+        if (p[1] == '/')
+          {
+             memmove(p, p + 1, --len - (p - result));
+             result[len] = '\0';
+          }
+        else
+          if (p[1] == '.'
+              && p[2] == '.')
+            {
+               // remove `/../'
+               if (p[3] == '/')
+                 {
+                    char tmp;
+
+                    len -= p + 3 - q;
+                    memmove(q, p + 3, len - (q - result));
+                    result[len] = '\0';
+                    p = q;
+
+                    /* Update q correctly. */
+                    tmp = *p;
+                    *p = '\0';
+                    q = strrchr(result, '/');
+                    if (!q) q = result;
+                    *p = tmp;
+                 }
+               else
+                 // remove '/..$'
+                 if (p[3] == '\0')
+                   {
+                      len -= p + 2 - q;
+                      result[len] = '\0';
+                      q = p;
+                      ++p;
+                   }
+                 else
+                   {
+                      q = p;
+                      ++p;
+                   }
+            }
+          else
+            {
+               q = p;
+               ++p;
+            }
+     }
+
+   if (length)
+     *length = len;
+
+   return result;
+}
+
+
+/**
+ * @endcond
+ */
+
+/*============================================================================*
+ *                                 Global                                     *
+ *============================================================================*/
+
+Eina_Bool
+eina_file_init(void)
+{
+   _eina_file_log_dom = eina_log_domain_register("eina_file",
+                                                 EINA_LOG_COLOR_DEFAULT);
+   if (_eina_file_log_dom < 0)
+     {
+        EINA_LOG_ERR("Could not register log domain: eina_file");
+        return EINA_FALSE;
+     }
+
+   _eina_file_cache = eina_hash_string_djb2_new(NULL);
+   if (!_eina_file_cache)
+     {
+        ERR("Could not create cache.");
+        eina_log_domain_unregister(_eina_file_log_dom);
+        _eina_file_log_dom = -1;
+        return EINA_FALSE;
+     }
+
+   eina_lock_new(&_eina_file_lock_cache);
+
+   return EINA_TRUE;
+}
+
+Eina_Bool
+eina_file_shutdown(void)
+{
+   if (eina_hash_population(_eina_file_cache) > 0)
+     {
+        Eina_Iterator *it;
+        const char *key;
+
+        it = eina_hash_iterator_key_new(_eina_file_cache);
+        EINA_ITERATOR_FOREACH(it, key)
+          ERR("File [%s] still open !", key);
+        eina_iterator_free(it);
+     }
+
+   eina_hash_free(_eina_file_cache);
+
+   eina_lock_free(&_eina_file_lock_cache);
+
+   eina_log_domain_unregister(_eina_file_log_dom);
+   _eina_file_log_dom = -1;
+   return EINA_TRUE;
+}
+
+/*============================================================================*
+ *                                   API                                      *
+ *============================================================================*/
+
+
+EAPI char *
+eina_file_path_sanitize(const char *path)
+{
+   char *result = NULL;
+   size_t len;
+
+   if (!path) return NULL;
+
+   len = strlen(path);
+   if (len < 3) return NULL;
+
+   if (!evil_path_is_absolute(path))
+     {
+        DWORD l;
+
+        l = GetCurrentDirectory(0, NULL);
+        if (l > 0)
+          {
+             char *cwd;
+             DWORD l2;
+
+             cwd = alloca(sizeof(char) * (l + 1));
+             l2 = GetCurrentDirectory(l + 1, cwd);
+             if (l2 == l)
+               {
+                  char *tmp;
+
+                  len += l + 2;
+                  tmp = alloca(sizeof (char) * len);
+                  snprintf(tmp, len, "%s/%s", cwd, path);
+                  tmp[len - 1] = '\0';
+                  result = tmp;
+               }
+          }
+     }
+
+   return _eina_file_win32_escape(result ? result : path, &len);
+}
+
+EAPI Eina_Bool
+eina_file_dir_list(const char *dir,
+                   Eina_Bool recursive,
+                   Eina_File_Dir_List_Cb cb,
+                   void *data)
+{
+   WIN32_FIND_DATA file;
+   HANDLE h;
+   char *new_dir;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(cb,  EINA_FALSE);
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, EINA_FALSE);
+   EINA_SAFETY_ON_TRUE_RETURN_VAL(dir[0] == '\0', EINA_FALSE);
+
+   if (!_eina_file_win32_is_dir(dir))
+     return EINA_FALSE;
+
+   new_dir = _eina_file_win32_dir_new(dir);
+   if (!new_dir)
+      return EINA_FALSE;
+
+   h = _eina_file_win32_first_file(new_dir, &file);
+
+   if (h == INVALID_HANDLE_VALUE)
+      return EINA_FALSE;
+
+   do
+     {
+        char *filename;
+
+# ifdef UNICODE
+        filename = evil_wchar_to_char(file.cFileName);
+# else
+        filename = file.cFileName;
+# endif /* ! UNICODE */
+        if (!strcmp(filename, ".") || !strcmp(filename, ".."))
+           continue;
+
+        cb(filename, dir, data);
+
+        if (recursive == EINA_TRUE)
+          {
+             char *path;
+
+             path = alloca(strlen(dir) + strlen(filename) + 2);
+             strcpy(path, dir);
+             strcat(path, "/");
+             strcat(path, filename);
+
+             if (!(file.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
+                continue;
+
+             eina_file_dir_list(path, recursive, cb, data);
+          }
+
+# ifdef UNICODE
+        free(filename);
+# endif /* UNICODE */
+
+     } while (FindNextFile(h, &file));
+   FindClose(h);
+
+   return EINA_TRUE;
+}
+
+EAPI Eina_Array *
+eina_file_split(char *path)
+{
+   Eina_Array *ea;
+   char *current;
+   size_t length;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   ea = eina_array_new(16);
+
+   if (!ea)
+      return NULL;
+
+   for (current = strchr(path, '\\');
+        current;
+        path = current + 1, current = strchr(path, '\\'))
+     {
+        length = current - path;
+
+        if (length <= 0)
+           continue;
+
+        eina_array_push(ea, path);
+        *current = '\0';
+     }
+
+   if (*path != '\0')
+        eina_array_push(ea, path);
+
+   return ea;
+}
+
+EAPI Eina_Iterator *
+eina_file_ls(const char *dir)
+{
+   Eina_File_Iterator *it;
+   char               *new_dir;
+   size_t              length;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
+
+   if (!dir || !*dir)
+      return NULL;
+
+   if (!_eina_file_win32_is_dir(dir))
+     return NULL;
+
+   length = strlen(dir);
+
+   it = calloc(1, sizeof (Eina_File_Iterator) + length);
+   if (!it)
+      return NULL;
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   new_dir = _eina_file_win32_dir_new(dir);
+   if (!new_dir)
+      goto free_it;
+
+   it->handle = _eina_file_win32_first_file(new_dir, &it->data);
+   free(new_dir);
+   if (it->handle == INVALID_HANDLE_VALUE)
+     goto free_it;
+
+   memcpy(it->dir, dir, length + 1);
+   if (dir[length - 1] != '\\')
+      it->length = length;
+   else
+      it->length = length - 1;
+   _eina_file_win32_backslash_change(it->dir);
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_ls_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_ls_iterator_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_ls_iterator_free);
+
+   return &it->iterator;
+
+ free_it:
+   free(it);
+
+   return NULL;
+}
+
+EAPI Eina_Iterator *
+eina_file_direct_ls(const char *dir)
+{
+   Eina_File_Direct_Iterator *it;
+   char                      *new_dir;
+   size_t                     length;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
+
+   if (!dir || !*dir)
+      return NULL;
+
+   length = strlen(dir);
+
+   if (length + 12 + 2 >= MAX_PATH)
+      return NULL;
+
+   it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
+   if (!it)
+      return NULL;
+
+   EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
+
+   new_dir = _eina_file_win32_dir_new(dir);
+   if (!new_dir)
+      goto free_it;
+
+   it->handle = _eina_file_win32_first_file(new_dir, &it->data);
+   free(new_dir);
+   if (it->handle == INVALID_HANDLE_VALUE)
+     goto free_it;
+
+   memcpy(it->dir, dir, length + 1);
+   it->length = length;
+   _eina_file_win32_backslash_change(it->dir);
+
+   memcpy(it->info.path, dir, length);
+   if (dir[length - 1] == '\\')
+      it->info.name_start = length;
+   else
+     {
+        it->info.path[length] = '\\';
+        it->info.name_start = length + 1;
+     }
+   _eina_file_win32_backslash_change(it->info.path);
+
+   it->iterator.version = EINA_ITERATOR_VERSION;
+   it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_win32_direct_ls_iterator_next);
+   it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(_eina_file_win32_direct_ls_iterator_container);
+   it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_win32_direct_ls_iterator_free);
+
+   return &it->iterator;
+
+ free_it:
+   free(it);
+
+   return NULL;
+}
+
+EAPI Eina_Iterator *
+eina_file_stat_ls(const char *dir)
+{
+   return eina_file_direct_ls(dir);
+}
+
+EAPI Eina_File *
+eina_file_open(const char *path, Eina_Bool shared)
+{
+   Eina_File *file;
+   Eina_File *n;
+   char *filename;
+   HANDLE handle;
+   HANDLE fm;
+   WIN32_FILE_ATTRIBUTE_DATA fad;
+   ULARGE_INTEGER length;
+   ULARGE_INTEGER mtime;
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
+
+   filename = eina_file_path_sanitize(path);
+   if (!filename) return NULL;
+
+   /* FIXME: how to emulate shm_open ? Just OpenFileMapping ? */
+#if 0
+   if (shared)
+     handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
+                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,
+                         NULL);
+   else
+#endif
+     handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
+                         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,
+                         NULL);
+
+   if (handle == INVALID_HANDLE_VALUE)
+     return NULL;
+
+   fm = CreateFileMapping(handle, NULL, PAGE_READONLY, 0, 0, NULL);
+   if (!fm)
+     goto close_handle;
+
+   if (!GetFileAttributesEx(filename, GetFileExInfoStandard, &fad))
+     goto close_fm;
+
+   length.u.LowPart = fad.nFileSizeLow;
+   length.u.HighPart = fad.nFileSizeHigh;
+   mtime.u.LowPart = fad.ftLastWriteTime.dwLowDateTime;
+   mtime.u.HighPart = fad.ftLastWriteTime.dwHighDateTime;
+
+   eina_lock_take(&_eina_file_lock_cache);
+
+   file = eina_hash_find(_eina_file_cache, filename);
+   if (file &&
+       (file->mtime == mtime.QuadPart && file->length == length.QuadPart))
+     {
+        file->delete_me = EINA_TRUE;
+        eina_hash_del(_eina_file_cache, file->filename, file);
+        _eina_file_real_close(file);
+        file = NULL;
+     }
+
+   if (!file)
+     {
+        n = malloc(sizeof (Eina_File) + strlen(filename) + 1);
+        if (!n)
+          {
+             eina_lock_release(&_eina_file_lock_cache);
+             goto close_fm;
+          }
+
+        n->filename = (char*) (n + 1);
+        strcpy((char*) n->filename, filename);
+        n->map = eina_hash_new(EINA_KEY_LENGTH(_eina_file_map_key_length),
+                               EINA_KEY_CMP(_eina_file_map_key_cmp),
+                               EINA_KEY_HASH(_eina_file_map_key_hash),
+                               EINA_FREE_CB(_eina_file_map_close),
+                               3);
+        n->rmap = eina_hash_pointer_new(NULL);
+        n->global_map = MAP_FAILED;
+        n->global_refcount = 0;
+        n->length = length.QuadPart;
+        n->mtime = mtime.QuadPart;
+        n->refcount = 0;
+        n->handle = handle;
+        n->fm = fm;
+        n->shared = shared;
+        n->delete_me = EINA_FALSE;
+        eina_lock_new(&n->lock);
+        eina_hash_direct_add(_eina_file_cache, n->filename, n);
+     }
+   else
+     {
+        CloseHandle(fm);
+        CloseHandle(handle);
+
+        n = file;
+     }
+   eina_lock_take(&n->lock);
+   n->refcount++;
+   eina_lock_release(&n->lock);
+
+   eina_lock_release(&_eina_file_lock_cache);
+
+   free(filename);
+
+   return n;
+
+ close_fm:
+   CloseHandle(fm);
+ close_handle:
+   CloseHandle(handle);
+
+   return NULL;
+}
+
+EAPI void
+eina_file_close(Eina_File *file)
+{
+   EINA_SAFETY_ON_NULL_RETURN(file);
+
+   eina_lock_take(&file->lock);
+   file->refcount--;
+   eina_lock_release(&file->lock);
+
+   if (file->refcount != 0) return ;
+   eina_lock_take(&_eina_file_lock_cache);
+
+   eina_hash_del(_eina_file_cache, file->filename, file);
+   _eina_file_real_close(file);
+   
+   eina_lock_release(&_eina_file_lock_cache);
+}
+
+EAPI size_t
+eina_file_size_get(Eina_File *file)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
+   return file->length;
+}
+
+EAPI time_t
+eina_file_mtime_get(Eina_File *file)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0);
+  return file->mtime;
+}
+
+EAPI const char *
+eina_file_filename_get(Eina_File *file)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+   return file->filename;
+}
+
+EAPI void *
+eina_file_map_all(Eina_File *file, Eina_File_Populate rule __UNUSED__)
+{
+   EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+   eina_lock_take(&file->lock);
+   if (file->global_map == MAP_FAILED)
+     {
+        void  *data;
+
+        data = MapViewOfFile(file->fm, FILE_MAP_READ,
+                             0, 0, file->length);
+        if (!data)
+          file->global_map = MAP_FAILED;
+        else
+          file->global_map = data;
+     }
+
+   if (file->global_map != MAP_FAILED)
+     {
+        file->global_refcount++;
+        return file->global_map;
+     }
+
+   eina_lock_release(&file->lock);
+   return NULL;
+}
+
+EAPI void *
+eina_file_map_new(Eina_File *file, Eina_File_Populate rule,
+                  unsigned long int offset, unsigned long int length)
+{
+   Eina_File_Map *map;
+   unsigned long int key[2];
+
+   EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+   if (offset > file->length)
+     return NULL;
+   if (offset + length > file->length)
+     return NULL;
+
+   if (offset == 0 && length == file->length)
+     return eina_file_map_all(file, rule);
+
+   key[0] = offset;
+   key[1] = length;
+
+   eina_lock_take(&file->lock);
+
+   map = eina_hash_find(file->map, &key);
+   if (!map)
+     {
+        void  *data;
+
+        map = malloc(sizeof (Eina_File_Map));
+        if (!map) return NULL;
+
+        data = MapViewOfFile(file->fm, FILE_MAP_READ,
+                             offset & 0xffff0000,
+                             offset & 0x0000ffff,
+                             length);
+        if (!data)
+          map->map = MAP_FAILED;
+        else
+          map->map = data;
+
+        map->offset = offset;
+        map->length = length;
+        map->refcount = 0;
+
+        if (map->map == MAP_FAILED)
+          {
+             free(map);
+             return NULL;
+          }
+
+        eina_hash_add(file->map, &key, map);
+        eina_hash_direct_add(file->rmap, map->map, map);
+     }
+
+   map->refcount++;
+
+   eina_lock_release(&file->lock);
+
+   return map->map;
+}
+
+EAPI void
+eina_file_map_free(Eina_File *file, void *map)
+{
+   EINA_SAFETY_ON_NULL_RETURN(file);
+
+   eina_lock_take(&file->lock);
+
+   if (file->global_map == map)
+     {
+        file->global_refcount--;
+
+        if (file->global_refcount > 0) goto on_exit;
+
+        UnmapViewOfFile(file->global_map);
+        file->global_map = MAP_FAILED;
+     }
+   else
+     {
+        Eina_File_Map *em;
+        unsigned long int key[2];
+
+        em = eina_hash_find(file->rmap, &map);
+        if (!em) return ;
+
+        em->refcount--;
+
+        if (em->refcount > 0) goto on_exit;
+
+        key[0] = em->offset;
+        key[1] = em->length;
+
+        eina_hash_del(file->rmap, &map, em);
+        eina_hash_del(file->map, &key, em);
+     }
+
+ on_exit:
+   eina_lock_release(&file->lock);
+}