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:
Vincent Torri 2011-04-15 07:03:17 +00:00
parent 8547ebf47f
commit c87ae61fb8
1 changed files with 418 additions and 1 deletions

View File

@ -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);
}
}