forked from enlightenment/efl
Eina: eina_file: port API to Windows
Currently, that code can potentially fail on Windows 64 bits as long is of size 32 bits and not 64 bits. All the file length and offset must be changed to something that fit the arch, like size_t, or use always uint64_t SVN revision: 58680
This commit is contained in:
parent
8547ebf47f
commit
c87ae61fb8
|
@ -41,7 +41,7 @@ void *alloca (size_t);
|
|||
#include <windows.h>
|
||||
#undef WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include <Evil.h>
|
||||
//#include <Evil.h>
|
||||
|
||||
#include "eina_config.h"
|
||||
#include "eina_private.h"
|
||||
|
@ -50,6 +50,8 @@ void *alloca (size_t);
|
|||
#include "eina_safety_checks.h"
|
||||
#include "eina_file.h"
|
||||
#include "eina_stringshare.h"
|
||||
#include "eina_hash.h"
|
||||
#include "eina_list.h"
|
||||
|
||||
/*============================================================================*
|
||||
* Local *
|
||||
|
@ -59,8 +61,33 @@ void *alloca (size_t);
|
|||
* @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
|
||||
{
|
||||
|
@ -88,6 +115,43 @@ struct _Eina_File_Direct_Iterator
|
|||
char dir[1];
|
||||
};
|
||||
|
||||
struct _Eina_File
|
||||
{
|
||||
const char *filename;
|
||||
|
||||
Eina_Hash *map;
|
||||
Eina_Hash *rmap;
|
||||
void *global_map;
|
||||
|
||||
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_List *_eina_file_cache_lru = NULL;
|
||||
static Eina_List *_eina_file_cache_delete = NULL;
|
||||
|
||||
static int _eina_file_log_dom = -1;
|
||||
|
||||
static void
|
||||
_eina_file_win32_backslash_change(char *dir)
|
||||
{
|
||||
|
@ -376,6 +440,105 @@ _eina_file_win32_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
|
|||
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));
|
||||
}
|
||||
|
||||
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(EINA_FREE_CB(_eina_file_real_close));
|
||||
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;
|
||||
}
|
||||
|
||||
return EINA_TRUE;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
eina_file_shutdown(void)
|
||||
{
|
||||
Eina_File *f;
|
||||
Eina_List *l;
|
||||
|
||||
EINA_LIST_FREE(_eina_file_cache_delete, f)
|
||||
_eina_file_real_close(f);
|
||||
|
||||
EINA_LIST_FOREACH(_eina_file_cache_lru, l, f)
|
||||
eina_hash_del(_eina_file_cache, f->filename, f);
|
||||
|
||||
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_log_domain_unregister(_eina_file_log_dom);
|
||||
_eina_file_log_dom = -1;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @endcond
|
||||
|
@ -599,3 +762,257 @@ eina_file_stat_ls(const char *dir)
|
|||
{
|
||||
return eina_file_direct_ls(dir);
|
||||
}
|
||||
|
||||
EAPI Eina_File *
|
||||
eina_file_open(const char *filename, Eina_Bool shared)
|
||||
{
|
||||
Eina_File *file;
|
||||
Eina_File *n;
|
||||
HANDLE handle;
|
||||
HANDLE fm;
|
||||
WIN32_FILE_ATTRIBUTE_DATA fad;
|
||||
ULARGE_INTEGER length;
|
||||
ULARGE_INTEGER mtime;
|
||||
Eina_Bool create = EINA_FALSE;
|
||||
|
||||
/* FIXME: always open absolute path (need to fix filename according to current
|
||||
directory) */
|
||||
|
||||
if (shared)
|
||||
/* FIXME: shm_open is maybe not really that */
|
||||
handle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY,
|
||||
NULL);
|
||||
else
|
||||
handle = CreateFile(filename, GENERIC_READ, 0,
|
||||
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;
|
||||
|
||||
file = eina_hash_find(_eina_file_cache, filename);
|
||||
if (file &&
|
||||
(file->mtime != mtime.QuadPart || file->length != length.QuadPart))
|
||||
{
|
||||
create = EINA_TRUE;
|
||||
|
||||
if (file->refcount == 0)
|
||||
{
|
||||
_eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file);
|
||||
eina_hash_del(_eina_file_cache, file->filename, file);
|
||||
|
||||
file = NULL;
|
||||
}
|
||||
else if (!file->delete_me)
|
||||
{
|
||||
file->delete_me = EINA_TRUE;
|
||||
_eina_file_cache_delete = eina_list_prepend(_eina_file_cache_delete, file);
|
||||
}
|
||||
}
|
||||
|
||||
if (!file || create)
|
||||
{
|
||||
n = calloc(1, sizeof (Eina_File));
|
||||
if (!n)
|
||||
goto close_fm;
|
||||
|
||||
n->filename = eina_stringshare_add(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->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_hash_set(_eina_file_cache, filename, n);
|
||||
}
|
||||
else
|
||||
{
|
||||
CloseHandle(fm);
|
||||
CloseHandle(handle);
|
||||
|
||||
n = file;
|
||||
|
||||
if (n->refcount == 0)
|
||||
_eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n);
|
||||
}
|
||||
|
||||
n->refcount++;
|
||||
|
||||
return n;
|
||||
|
||||
close_fm:
|
||||
CloseHandle(fm);
|
||||
close_handle:
|
||||
CloseHandle(handle);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
eina_file_close(Eina_File *file)
|
||||
{
|
||||
file->refcount--;
|
||||
|
||||
if (file->refcount != 0) return ;
|
||||
|
||||
if (file->delete_me)
|
||||
{
|
||||
_eina_file_cache_delete = eina_list_remove(_eina_file_cache_delete, file);
|
||||
_eina_file_real_close(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
_eina_file_cache_lru = eina_list_prepend(_eina_file_cache_lru, file);
|
||||
}
|
||||
}
|
||||
|
||||
EAPI unsigned long int
|
||||
eina_file_size_get(Eina_File *file)
|
||||
{
|
||||
return file->length;
|
||||
}
|
||||
|
||||
EAPI time_t
|
||||
eina_file_mtime_get(Eina_File *file)
|
||||
{
|
||||
return file->mtime;
|
||||
}
|
||||
|
||||
EAPI const char *
|
||||
eina_file_filename_get(Eina_File *file)
|
||||
{
|
||||
return file->filename;
|
||||
}
|
||||
|
||||
EAPI void *
|
||||
eina_file_map_all(Eina_File *file, Eina_File_Populate rule __UNUSED__)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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];
|
||||
|
||||
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;
|
||||
|
||||
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++;
|
||||
|
||||
return map->map;
|
||||
}
|
||||
|
||||
EAPI void
|
||||
eina_file_map_free(Eina_File *file, void *map)
|
||||
{
|
||||
if (file->global_map == map)
|
||||
{
|
||||
file->global_refcount--;
|
||||
|
||||
if (file->global_refcount > 0) return ;
|
||||
|
||||
/* FIXME: are we sure that file->global_map != MAP_FAILED ? */
|
||||
if (file->global_map != MAP_FAILED)
|
||||
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) return ;
|
||||
|
||||
key[0] = em->offset;
|
||||
key[1] = em->length;
|
||||
|
||||
eina_hash_del(file->rmap, &map, em);
|
||||
eina_hash_del(file->map, &key, em);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue