/* EINA - EFL data type library
* Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
- * Copyright (C) 2010 Cedric Bail
+ * Copyright (C) 2010-2011 Cedric Bail
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
void *alloca (size_t);
#endif
+#include <stdlib.h>
#include <string.h>
#include <stddef.h>
-#include <dirent.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <sys/mman.h>
+#ifdef HAVE_SYS_MMAN_H
+# include <sys/mman.h>
+#endif
#include <fcntl.h>
#define PATH_DELIM '/'
-#ifdef __sun
-# ifndef NAME_MAX
-# define NAME_MAX 255
-# endif
-#endif
-
#include "eina_config.h"
#include "eina_private.h"
#include "eina_stringshare.h"
#include "eina_hash.h"
#include "eina_list.h"
+#include "eina_lock.h"
+#include "eina_mmap.h"
+#include "eina_log.h"
+#include "eina_xattr.h"
+
+#ifdef HAVE_ESCAPE_H
+# include <Escape.h>
+#endif
/*============================================================================*
* Local *
*============================================================================*/
+/**
+ * @cond LOCAL
+ */
+
#ifndef EINA_LOG_COLOR_DEFAULT
#define EINA_LOG_COLOR_DEFAULT EINA_COLOR_CYAN
#endif
#endif
#define DBG(...) EINA_LOG_DOM_DBG(_eina_file_log_dom, __VA_ARGS__)
-/**
- * @cond LOCAL
- */
-typedef struct _Eina_File_Iterator Eina_File_Iterator;
-typedef struct _Eina_File_Map Eina_File_Map;
+#define EINA_SMALL_PAGE 4096
+# define EINA_HUGE_PAGE 16 * 1024 * 1024
+#ifdef HAVE_DIRENT_H
+typedef struct _Eina_File_Iterator Eina_File_Iterator;
struct _Eina_File_Iterator
{
Eina_Iterator iterator;
char dir[1];
};
+#endif
struct _Eina_File
{
Eina_Hash *rmap;
void *global_map;
- unsigned long length;
+ Eina_Lock lock;
+
+ unsigned long long length;
time_t mtime;
+ ino_t inode;
+#ifdef _STAT_VER_LINUX
+ unsigned long int mtime_nsec;
+#endif
int refcount;
int global_refcount;
Eina_Bool shared : 1;
Eina_Bool delete_me : 1;
+ Eina_Bool global_faulty : 1;
};
+typedef struct _Eina_File_Map Eina_File_Map;
struct _Eina_File_Map
{
void *map;
unsigned long int length;
int refcount;
+
+ Eina_Bool hugetlb : 1;
+ Eina_Bool faulty : 1;
};
static Eina_Hash *_eina_file_cache = NULL;
-static Eina_List *_eina_file_cache_lru = NULL;
-static Eina_List *_eina_file_cache_delete = NULL;
+static Eina_Lock _eina_file_lock_cache;
static int _eina_file_log_dom = -1;
* The code and description of the issue can be found at :
* http://womble.decadent.org.uk/readdir_r-advisory.html
*/
-static size_t
-_eina_dirent_buffer_size(DIR *dirp)
+#ifdef HAVE_DIRENT_H
+static long
+_eina_name_max(DIR *dirp)
{
long name_max;
- size_t name_end;
#if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
# endif
# endif
#endif
+
+ return name_max;
+}
+
+static size_t
+_eina_dirent_buffer_size(DIR *dirp)
+{
+ long name_max = _eina_name_max(dirp);
+ size_t name_end;
+
name_end = (size_t) offsetof(struct dirent, d_name) + name_max + 1;
return (name_end > sizeof (struct dirent) ? name_end : sizeof (struct dirent));
static Eina_Bool
_eina_file_stat_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
{
- struct stat st;
+ Eina_Stat st;
if (!_eina_file_direct_ls_iterator_next(it, data))
return EINA_FALSE;
if (it->info.type == EINA_FILE_UNKNOWN)
{
-#ifdef HAVE_FSTATAT
- int fd;
-
- fd = dirfd(it->dirp);
- if (fstatat(fd, it->info.path + it->info.name_start, &st, 0))
-#else
- if (stat(it->info.path, &st))
-#endif
+ if (eina_file_statat(it->dirp, &it->info, &st) != 0)
it->info.type = EINA_FILE_UNKNOWN;
- else
- {
- if (S_ISREG(st.st_mode))
- it->info.type = EINA_FILE_REG;
- else if (S_ISDIR(st.st_mode))
- it->info.type = EINA_FILE_DIR;
- else if (S_ISCHR(st.st_mode))
- it->info.type = EINA_FILE_CHR;
- else if (S_ISBLK(st.st_mode))
- it->info.type = EINA_FILE_BLK;
- else if (S_ISFIFO(st.st_mode))
- it->info.type = EINA_FILE_FIFO;
- else if (S_ISLNK(st.st_mode))
- it->info.type = EINA_FILE_LNK;
- else if (S_ISSOCK(st.st_mode))
- it->info.type = EINA_FILE_SOCK;
- else
- it->info.type = EINA_FILE_UNKNOWN;
- }
}
return EINA_TRUE;
}
+#endif
static void
_eina_file_real_close(Eina_File *file)
{
+ if (file->refcount != 0) return;
+
eina_hash_free(file->rmap);
eina_hash_free(file->map);
close(file->fd);
- eina_stringshare_del(file->filename);
-
free(file);
}
^ eina_hash_int64(&key[1], sizeof (unsigned long int));
}
-static void
-_eina_file_map_rule_apply(Eina_File_Populate rule, void *addr, unsigned long int size)
+#ifndef MAP_POPULATE
+static unsigned int
+_eina_file_map_populate(char *map, unsigned int size, Eina_Bool hugetlb)
{
- int flag;
+ unsigned int r = 0xDEADBEEF;
+ unsigned int i;
+ unsigned int s;
+
+ s = hugetlb ? EINA_HUGE_PAGE : EINA_SMALL_PAGE;
+
+ for (i = 0; i < size; i += s)
+ r ^= map[i];
+
+ r ^= map[size];
+
+ return r;
+}
+#endif
+
+static int
+_eina_file_map_rule_apply(Eina_File_Populate rule, void *addr, unsigned long int size, Eina_Bool hugetlb)
+{
+ int tmp = 42;
+ int flag = MADV_RANDOM;
switch (rule)
{
case EINA_FILE_RANDOM: flag = MADV_RANDOM; break;
case EINA_FILE_SEQUENTIAL: flag = MADV_SEQUENTIAL; break;
- case EINA_FILE_WILLNEED:
- case EINA_FILE_POPULATE:
- flag = MADV_WILLNEED;
- break;
+ case EINA_FILE_POPULATE: flag = MADV_WILLNEED; break;
+ case EINA_FILE_WILLNEED: flag = MADV_WILLNEED; break;
}
madvise(addr, size, flag);
+
+#ifndef MAP_POPULATE
+ if (rule == EINA_FILE_POPULATE)
+ tmp ^= _eina_file_map_populate(addr, size, hugetlb);
+#else
+ (void) hugetlb;
+#endif
+
+ return tmp;
}
+static Eina_Bool
+_eina_file_timestamp_compare(Eina_File *f, struct stat *st)
+{
+ if (f->mtime != st->st_mtime) return EINA_FALSE;
+ if (f->length != (unsigned long long) st->st_size) return EINA_FALSE;
+ if (f->inode != st->st_ino) return EINA_FALSE;
+#ifdef _STAT_VER_LINUX
+# if (defined __USE_MISC && defined st_mtime)
+ if (f->mtime_nsec != (unsigned long int)st->st_mtim.tv_nsec)
+ return EINA_FALSE;
+# else
+ if (f->mtime_nsec != (unsigned long int)st->st_mtimensec)
+ return EINA_FALSE;
+# endif
+#endif
+ return EINA_TRUE;
+}
+
+static void
+slprintf(char *str, size_t size, const char *format, ...)
+{
+ va_list ap;
+
+ va_start(ap, format);
+
+ vsnprintf(str, size, format, ap);
+ str[size - 1] = 0;
+
+ va_end(ap);
+}
+
+static char *
+_eina_file_escape(const char *path, int *length)
+{
+ char *result = strdup(path ? path : "");
+ char *p = result;
+ char *q = result;
+ int 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)
{
return EINA_FALSE;
}
- _eina_file_cache = eina_hash_string_djb2_new(EINA_FREE_CB(_eina_file_real_close));
+ _eina_file_cache = eina_hash_string_djb2_new(NULL);
if (!_eina_file_cache)
{
ERR("Could not create cache.");
return EINA_FALSE;
}
+ eina_lock_new(&_eina_file_lock_cache);
+
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;
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_FALSE;
+ return EINA_TRUE;
}
-/**
- * @endcond
- */
+void
+eina_file_mmap_faulty(void *addr, long page_size)
+{
+ Eina_File_Map *m;
+ Eina_File *f;
+ Eina_Iterator *itf;
+ Eina_Iterator *itm;
-/*============================================================================*
- * Global *
- *============================================================================*/
+ /* NOTE: I actually don't know if other thread are running, I will try to take the lock.
+ It may be possible that if other thread are not running and they were in the middle of
+ accessing an Eina_File this lock are still taken and we will result as a deadlock. */
+ eina_lock_take(&_eina_file_lock_cache);
+
+ itf = eina_hash_iterator_data_new(_eina_file_cache);
+ EINA_ITERATOR_FOREACH(itf, f)
+ {
+ Eina_Bool faulty = EINA_FALSE;
+
+ eina_lock_take(&f->lock);
+
+ if (f->global_map)
+ {
+ if ((unsigned char *) addr < (((unsigned char *)f->global_map) + f->length) &&
+ (((unsigned char *) addr) + page_size) >= (unsigned char *) f->global_map)
+ {
+ f->global_faulty = EINA_TRUE;
+ faulty = EINA_TRUE;
+ }
+ }
+
+ if (!faulty)
+ {
+ itm = eina_hash_iterator_data_new(f->map);
+ EINA_ITERATOR_FOREACH(itm, m)
+ {
+ if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) &&
+ (((unsigned char *) addr) + page_size) >= (unsigned char *) m->map)
+ {
+ m->faulty = EINA_TRUE;
+ faulty = EINA_TRUE;
+ break;
+ }
+ }
+ eina_iterator_free(itm);
+ }
+
+ eina_lock_release(&f->lock);
+
+ if (faulty) break;
+ }
+ eina_iterator_free(itf);
+
+ eina_lock_release(&_eina_file_lock_cache);
+}
/*============================================================================*
* API *
*============================================================================*/
+EAPI char *
+eina_file_path_sanitize(const char *path)
+{
+ char *result = NULL;
+ int len;
+
+ if (!path) return NULL;
+
+ len = strlen(path);
+
+ if (*path != '/')
+ {
+ char cwd[PATH_MAX];
+ char *tmp = NULL;
+
+ tmp = getcwd(cwd, PATH_MAX);
+ if (!tmp) return NULL;
+
+ len += strlen(cwd) + 2;
+ tmp = alloca(sizeof (char) * len);
+
+ slprintf(tmp, len, "%s/%s", cwd, path);
+
+ result = tmp;
+ }
+
+ return _eina_file_escape(result ? result : path, &len);
+}
+
EAPI Eina_Bool
eina_file_dir_list(const char *dir,
Eina_Bool recursive,
EAPI Eina_Iterator *
eina_file_ls(const char *dir)
{
+#ifdef HAVE_DIRENT_H
Eina_File_Iterator *it;
size_t length;
- if (!dir)
- return NULL;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
length = strlen(dir);
if (length < 1)
it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
return &it->iterator;
+#else
+ (void) dir;
+ return NULL;
+#endif
}
EAPI Eina_Iterator *
eina_file_direct_ls(const char *dir)
{
+#ifdef HAVE_DIRENT_H
Eina_File_Direct_Iterator *it;
size_t length;
- if (!dir)
- return NULL;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
length = strlen(dir);
if (length < 1)
return NULL;
- if (length + NAME_MAX + 2 >= EINA_PATH_MAX)
- return NULL;
-
it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
if (!it)
return NULL;
return NULL;
}
+ if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX)
+ {
+ _eina_file_direct_ls_iterator_free(it);
+ return NULL;
+ }
+
memcpy(it->dir, dir, length + 1);
it->length = length;
it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
return &it->iterator;
+#else
+ (void) dir;
+ return NULL;
+#endif
}
EAPI Eina_Iterator *
eina_file_stat_ls(const char *dir)
{
+#ifdef HAVE_DIRENT_H
Eina_File_Direct_Iterator *it;
size_t length;
- if (!dir)
- return NULL;
+ EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
length = strlen(dir);
if (length < 1)
return NULL;
- if (length + NAME_MAX + 2 >= EINA_PATH_MAX)
- return NULL;
-
it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
if (!it)
return NULL;
return NULL;
}
+ if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX)
+ {
+ _eina_file_direct_ls_iterator_free(it);
+ return NULL;
+ }
+
memcpy(it->dir, dir, length + 1);
it->length = length;
it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
return &it->iterator;
+#else
+ (void) dir;
+ return NULL;
+#endif
}
EAPI Eina_File *
-eina_file_open(const char *filename, Eina_Bool shared)
+eina_file_open(const char *path, Eina_Bool shared)
{
Eina_File *file;
Eina_File *n;
+ char *filename;
struct stat file_stat;
- int fd;
- Eina_Bool create = EINA_FALSE;
+ int fd = -1;
+#ifdef HAVE_EXECVP
+ int flags;
+#endif
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
- /* FIXME: always open absolute path (need to fix filename according to current
- directory) */
+ filename = eina_file_path_sanitize(path);
+ if (!filename) return NULL;
if (shared)
- fd = shm_open(filename, O_RDONLY | O_CLOEXEC, ACCESSPERMS);
+#ifdef HAVE_SHMOPEN
+ fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
+#else
+ goto on_error;
+#endif
else
- fd = open(filename, O_RDONLY | O_CLOEXEC, ACCESSPERMS);
+ fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
- if (fd < 0) return NULL;
+ if (fd < 0) goto on_error;
+
+#ifdef HAVE_EXECVP
+ flags = fcntl(fd, F_GETFD);
+ if (flags == -1)
+ goto on_error;
+
+ flags |= FD_CLOEXEC;
+ if (fcntl(fd, F_SETFD, flags) == -1)
+ goto on_error;
+#endif
if (fstat(fd, &file_stat))
- {
- close(fd);
- return NULL;
- }
+ goto on_error;
+
+ eina_lock_take(&_eina_file_lock_cache);
file = eina_hash_find(_eina_file_cache, filename);
- if (file && (file->mtime != file_stat.st_mtime
- || file->length != file_stat.st_size))
+ if ((file) && _eina_file_timestamp_compare(file, &file_stat))
{
- 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);
- }
+ file->delete_me = EINA_TRUE;
+ eina_hash_del(_eina_file_cache, file->filename, file);
+ _eina_file_real_close(file);
+ file = NULL;
}
- if (!file || create)
+ if (!file)
{
- n = malloc(sizeof (Eina_File));
- if (!n) goto on_error;
-
- n->filename = eina_stringshare_add(filename);
+ n = malloc(sizeof (Eina_File) + strlen(filename) + 1);
+ if (!n)
+ {
+ eina_lock_release(&_eina_file_lock_cache);
+ goto on_error;
+ }
+
+ 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),
3);
n->rmap = eina_hash_pointer_new(NULL);
n->global_map = MAP_FAILED;
+ n->global_refcount = 0;
n->length = file_stat.st_size;
n->mtime = file_stat.st_mtime;
+#ifdef _STAT_VER_LINUX
+# if (defined __USE_MISC && defined st_mtime)
+ n->mtime_nsec = (unsigned long int)file_stat.st_mtim.tv_nsec;
+# else
+ n->mtime_nsec = (unsigned long int)file_stat.st_mtimensec;
+# endif
+#endif
+ n->inode = file_stat.st_ino;
n->refcount = 0;
n->fd = fd;
n->shared = shared;
n->delete_me = EINA_FALSE;
-
- eina_hash_set(_eina_file_cache, filename, n);
+ eina_lock_new(&n->lock);
+ eina_hash_direct_add(_eina_file_cache, n->filename, n);
}
else
{
close(fd);
-
n = file;
-
- if (n->refcount == 0)
- _eina_file_cache_lru = eina_list_remove(_eina_file_cache_lru, n);
}
-
+ eina_lock_take(&n->lock);
n->refcount++;
+ eina_lock_release(&n->lock);
+
+ eina_lock_release(&_eina_file_lock_cache);
+
+ free(filename);
return n;
on_error:
- close(fd);
+ free(filename);
+ if (fd >= 0) close(fd);
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 ;
+ if (file->refcount != 0) return;
+ eina_lock_take(&_eina_file_lock_cache);
- 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);
- }
+ eina_hash_del(_eina_file_cache, file->filename, file);
+ _eina_file_real_close(file);
+
+ eina_lock_release(&_eina_file_lock_cache);
}
-EAPI unsigned long int
+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;
}
eina_file_map_all(Eina_File *file, Eina_File_Populate rule)
{
int flags = MAP_SHARED;
+ void *ret = NULL;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+// bsd people will lack this feature
+#ifdef MAP_POPULATE
if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
+#endif
+#ifdef MAP_HUGETLB
+ if (file->length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
+#endif
+ eina_mmap_safety_enabled_set(EINA_TRUE);
+ eina_lock_take(&file->lock);
if (file->global_map == MAP_FAILED)
file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
+#ifdef MAP_HUGETLB
+ if ((file->global_map == MAP_FAILED) && (flags & MAP_HUGETLB))
+ {
+ flags &= ~MAP_HUGETLB;
+ file->global_map = mmap(NULL, file->length, PROT_READ, flags, file->fd, 0);
+ }
+#endif
if (file->global_map != MAP_FAILED)
{
- _eina_file_map_rule_apply(rule, file->global_map, file->length);
+ Eina_Bool hugetlb = EINA_FALSE;
+
+#ifdef MAP_HUGETLB
+ hugetlb = !!(flags & MAP_HUGETLB);
+#endif
+ _eina_file_map_rule_apply(rule, file->global_map, file->length, hugetlb);
file->global_refcount++;
- return file->global_map;
+ ret = file->global_map;
}
- return NULL;
+
+ eina_lock_release(&file->lock);
+ return ret;
}
EAPI void *
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)
key[0] = offset;
key[1] = length;
+ eina_mmap_safety_enabled_set(EINA_TRUE);
+ eina_lock_take(&file->lock);
+
map = eina_hash_find(file->map, &key);
if (!map)
{
int flags = MAP_SHARED;
+// bsd people will lack this feature
+#ifdef MAP_POPULATE
if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
+#endif
+#ifdef MAP_HUGETLB
+ if (length > EINA_HUGE_PAGE) flags |= MAP_HUGETLB;
+#endif
map = malloc(sizeof (Eina_File_Map));
- if (!map) return NULL;
+ if (!map) goto on_error;
map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset);
+#ifdef MAP_HUGETLB
+ if (map->map == MAP_FAILED && (flags & MAP_HUGETLB))
+ {
+ flags &= ~MAP_HUGETLB;
+ map->map = mmap(NULL, length, PROT_READ, flags, file->fd, offset);
+ }
+
+ map->hugetlb = !!(flags & MAP_HUGETLB);
+#else
+ map->hugetlb = EINA_FALSE;
+#endif
map->offset = offset;
map->length = length;
map->refcount = 0;
- if (map->map == MAP_FAILED)
- {
- free(map);
- return NULL;
- }
+ if (map->map == MAP_FAILED) goto on_error;
eina_hash_add(file->map, &key, map);
eina_hash_direct_add(file->rmap, map->map, map);
map->refcount++;
- _eina_file_map_rule_apply(rule, map->map, length);
+ _eina_file_map_rule_apply(rule, map->map, length, map->hugetlb);
+
+ eina_lock_release(&file->lock);
return map->map;
+
+ on_error:
+ free(map);
+ eina_lock_release(&file->lock);
+
+ return NULL;
}
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) return ;
+ if (file->global_refcount > 0) goto on_exit;
munmap(file->global_map, file->length);
file->global_map = MAP_FAILED;
em->refcount--;
- if (em->refcount > 0) return ;
+ 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);
+}
+
+EAPI Eina_Bool
+eina_file_map_faulted(Eina_File *file, void *map)
+{
+ Eina_File_Map *em;
+
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
+
+ eina_lock_take(&file->lock);
+
+ if (file->global_map == map) return file->global_faulty;
+
+ em = eina_hash_find(file->rmap, &map);
+ if (!em) return EINA_FALSE;
+
+ return em->faulty;
}
+EAPI Eina_Iterator *
+eina_file_xattr_get(Eina_File *file)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+ return eina_xattr_fd_ls(file->fd);
+}
+
+EAPI Eina_Iterator *
+eina_file_xattr_value_get(Eina_File *file)
+{
+ EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
+
+ return eina_xattr_value_fd_ls(file->fd);
+}
+
+EAPI int
+eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st)
+{
+ struct stat buf;
+#ifdef HAVE_FSTATAT
+ int fd;
+#endif
+ EINA_SAFETY_ON_NULL_RETURN_VAL(info, -1);
+ EINA_SAFETY_ON_NULL_RETURN_VAL(st, -1);
+
+#ifdef HAVE_FSTATAT
+ fd = dirfd(container);
+ if (fstatat(fd, info->path + info->name_start, &buf, 0))
+#else
+ if (stat(info->path, &buf))
+#endif
+ {
+ if (info->type != EINA_FILE_LNK)
+ info->type = EINA_FILE_UNKNOWN;
+ return -1;
+ }
+
+ if (info->type == EINA_FILE_UNKNOWN)
+ {
+ if (S_ISREG(buf.st_mode))
+ info->type = EINA_FILE_REG;
+ else if (S_ISDIR(buf.st_mode))
+ info->type = EINA_FILE_DIR;
+ else if (S_ISCHR(buf.st_mode))
+ info->type = EINA_FILE_CHR;
+ else if (S_ISBLK(buf.st_mode))
+ info->type = EINA_FILE_BLK;
+ else if (S_ISFIFO(buf.st_mode))
+ info->type = EINA_FILE_FIFO;
+ else if (S_ISLNK(buf.st_mode))
+ info->type = EINA_FILE_LNK;
+ else if (S_ISSOCK(buf.st_mode))
+ info->type = EINA_FILE_SOCK;
+ else
+ info->type = EINA_FILE_UNKNOWN;
+ }
+
+ st->dev = buf.st_dev;
+ st->ino = buf.st_ino;
+ st->mode = buf.st_mode;
+ st->nlink = buf.st_nlink;
+ st->uid = buf.st_uid;
+ st->gid = buf.st_gid;
+ st->rdev = buf.st_rdev;
+ st->size = buf.st_size;
+ st->blksize = buf.st_blksize;
+ st->blocks = buf.st_blocks;
+ st->atime = buf.st_atime;
+ st->mtime = buf.st_mtime;
+ st->ctime = buf.st_ctime;
+#ifdef _STAT_VER_LINUX
+# if (defined __USE_MISC && defined st_mtime)
+ st->atimensec = buf.st_atim.tv_nsec;
+ st->mtimensec = buf.st_mtim.tv_nsec;
+ st->ctimensec = buf.st_ctim.tv_nsec;
+# else
+ st->atimensec = buf.st_atimensec;
+ st->mtimensec = buf.st_mtimensec;
+ st->ctimensec = buf.st_ctimensec;
+# endif
+#else
+ st->atimensec = 0;
+ st->mtimensec = 0;
+ st->ctimensec = 0;
+#endif
+ return 0;
+}