#include <windows.h>\r
#undef WIN32_LEAN_AND_MEAN\r
\r
-//#include <Evil.h>\r
+#include <Evil.h>\r
\r
#include "eina_config.h"\r
#include "eina_private.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
Eina_Hash *rmap;\r
void *global_map;\r
\r
+ Eina_Lock lock;\r
+\r
ULONGLONG length;\r
ULONGLONG mtime;\r
\r
};\r
\r
static Eina_Hash *_eina_file_cache = NULL;\r
-static Eina_List *_eina_file_cache_lru = NULL;\r
-static Eina_List *_eina_file_cache_delete = NULL;\r
+static Eina_Lock _eina_file_lock_cache;\r
\r
static int _eina_file_log_dom = -1;\r
\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
return EINA_FALSE;\r
}\r
\r
- _eina_file_cache = eina_hash_string_djb2_new(EINA_FREE_CB(_eina_file_real_close));\r
+ _eina_file_cache = eina_hash_string_djb2_new(NULL);\r
if (!_eina_file_cache)\r
{\r
ERR("Could not create cache.");\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
- Eina_File *f;\r
- Eina_List *l;\r
-\r
- EINA_LIST_FREE(_eina_file_cache_delete, f)\r
- _eina_file_real_close(f);\r
-\r
- EINA_LIST_FOREACH(_eina_file_cache_lru, l, f)\r
- eina_hash_del(_eina_file_cache, f->filename, f);\r
-\r
if (eina_hash_population(_eina_file_cache) > 0)\r
{\r
Eina_Iterator *it;\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
-/**\r
- * @endcond\r
- */\r
-\r
-/*============================================================================*\r
- * Global *\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
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
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
}\r
\r
EAPI Eina_File *\r
-eina_file_open(const char *filename, Eina_Bool shared)\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 mtime;\r
Eina_Bool create = EINA_FALSE;\r
\r
- /* FIXME: always open absolute path (need to fix filename according to current\r
- directory) */\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
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
+ (file->mtime == mtime.QuadPart && file->length == length.QuadPart))\r
{\r
- create = EINA_TRUE;\r
-\r
- if (file->refcount == 0)\r
- {\r
- _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file);\r
- eina_hash_del(_eina_file_cache, file->filename, file);\r
-\r
- file = NULL;\r
- }\r
- else if (!file->delete_me)\r
- {\r
- file->delete_me = EINA_TRUE;\r
- _eina_file_cache_delete = eina_list_prepend(_eina_file_cache_delete, file);\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 || create)\r
+ if (!file)\r
{\r
- n = calloc(1, sizeof (Eina_File));\r
+ n = malloc(sizeof (Eina_File) + strlen(filename) + 1);\r
if (!n)\r
- goto close_fm;\r
+ {\r
+ eina_lock_release(&_eina_file_lock_cache);\r
+ goto close_fm;\r
+ }\r
\r
- n->filename = eina_stringshare_add(filename);\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
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->fm = fm;\r
n->shared = shared;\r
n->delete_me = EINA_FALSE;\r
-\r
- eina_hash_set(_eina_file_cache, filename, n);\r
+ eina_lock_new(&n->lock);\r
+ eina_hash_direct_add(_eina_file_cache, n->filename, n);\r
}\r
else\r
{\r
CloseHandle(handle);\r
\r
n = file;\r
-\r
- if (n->refcount == 0)\r
- _eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n);\r
}\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
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
- if (file->delete_me)\r
- {\r
- _eina_file_cache_delete = eina_list_remove(_eina_file_cache_delete, file);\r
- _eina_file_real_close(file);\r
- }\r
- else\r
- {\r
- _eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file);\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
return file->global_map;\r
}\r
\r
+ eina_lock_release(&file->lock);\r
return NULL;\r
}\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
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
\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) return ;\r
+ if (file->global_refcount > 0) goto on_exit;\r
\r
- /* FIXME: are we sure that file->global_map != MAP_FAILED ? */\r
- if (file->global_map != MAP_FAILED)\r
- UnmapViewOfFile(file->global_map);\r
+ UnmapViewOfFile(file->global_map);\r
file->global_map = MAP_FAILED;\r
}\r
else\r
\r
em->refcount--;\r
\r
- if (em->refcount > 0) return ;\r
+ if (em->refcount > 0) goto on_exit;\r
\r
key[0] = em->offset;\r
key[1] = em->length;\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