efl/src/lib/eina/eina_file_posix.c

1588 lines
39 KiB
C
Raw Normal View History

/* EINA - EFL data type library
* Copyright (C) 2007-2008 Jorge Luis Zapata Muga, Vincent Torri
* 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
* 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
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <stdlib.h>
#include <string.h>
#include <stddef.h>
#include <stdint.h>
#ifdef HAVE_DIRENT_H
# include <dirent.h>
#endif
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_SYS_MMAN_H
# include <sys/mman.h>
#endif
#include <fcntl.h>
#if defined(__linux__)
# include <sys/syscall.h>
#endif
#ifdef HAVE_SYS_RESOURCE_H
# include <sys/resource.h>
#endif
#define PATH_DELIM '/'
#include "eina_config.h"
#include "eina_private.h"
#include "eina_alloca.h"
/* undefs EINA_ARG_NONULL() so NULL checks are not compiled out! */
#include "eina_safety_checks.h"
#include "eina_cpu.h"
#include "eina_file.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"
2012-01-03 07:24:15 -08:00
#include "eina_xattr.h"
#include "eina_file_common.h"
/*============================================================================*
* Local *
*============================================================================*/
2011-04-13 10:03:24 -07:00
/**
* @cond LOCAL
*/
#define EINA_SMALL_PAGE eina_cpu_page_size()
// FIXME: This assumes HugeTLB size of 2Mb. How to get this information at runtime?
#define EINA_HUGE_PAGE (2 * 1024 * 1024)
#define EINA_HUGE_PAGE_MIN (8 * EINA_HUGE_PAGE)
#ifdef HAVE_DIRENT_H
typedef struct _Eina_File_Iterator Eina_File_Iterator;
struct _Eina_File_Iterator
{
Eina_Iterator iterator;
DIR *dirp;
int length;
char dir[1];
};
#endif
int _eina_file_log_dom = -1;
/*
* This complex piece of code is needed due to possible race condition.
* The code and description of the issue can be found at :
* http://womble.decadent.org.uk/readdir_r-advisory.html
*/
#ifdef HAVE_DIRENT_H
static long
_eina_name_max(DIR *dirp EINA_UNUSED)
{
long name_max;
#if defined(HAVE_FPATHCONF) && defined(HAVE_DIRFD) && defined(_PC_NAME_MAX)
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
if (name_max == -1)
{
# if defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
# else
2010-11-03 10:32:07 -07:00
name_max = PATH_MAX;
# endif
}
#else
# if defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
# else
# ifdef _PC_NAME_MAX
# warning "buffer size for readdir_r cannot be determined safely, best effort, but racy"
name_max = pathconf(dirp, _PC_NAME_MAX);
# else
# error "buffer size for readdir_r cannot be determined safely"
# endif
# endif
#endif
return name_max;
}
static Eina_Bool
_eina_file_ls_iterator_next(Eina_File_Iterator *it, void **data)
{
struct dirent *dp;
char *name;
size_t length;
do
{
dp = readdir(it->dirp);
if (dp == NULL)
return EINA_FALSE;
}
while ((dp->d_name[0] == '.') &&
2010-07-27 19:37:05 -07:00
((dp->d_name[1] == '\0') ||
((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
#ifdef _DIRENT_HAVE_D_NAMLEN
length = dp->d_namlen;
#else
length = strlen(dp->d_name);
#endif
name = alloca(length + 2 + it->length);
2010-07-27 19:37:05 -07:00
memcpy(name, it->dir, it->length);
memcpy(name + it->length, "/", 1);
memcpy(name + it->length + 1, dp->d_name, length + 1);
2010-07-27 19:37:05 -07:00
*data = (char *)eina_stringshare_add(name);
return EINA_TRUE;
}
static DIR *
_eina_file_ls_iterator_container(Eina_File_Iterator *it)
{
return it->dirp;
}
static void
_eina_file_ls_iterator_free(Eina_File_Iterator *it)
{
closedir(it->dirp);
EINA_MAGIC_SET(&it->iterator, 0);
free(it);
}
2008-08-08 22:47:15 -07:00
typedef struct _Eina_File_Direct_Iterator Eina_File_Direct_Iterator;
struct _Eina_File_Direct_Iterator
{
Eina_Iterator iterator;
DIR *dirp;
int length;
Eina_File_Direct_Info info;
char dir[1];
};
static Eina_Bool
_eina_file_direct_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
{
struct dirent *dp;
size_t length;
do
{
dp = readdir(it->dirp);
if (dp == NULL)
return EINA_FALSE;
#ifdef _DIRENT_HAVE_D_NAMLEN
length = dp->d_namlen;
#else
2010-07-27 19:37:05 -07:00
length = strlen(dp->d_name);
#endif
if (it->info.name_start + length + 1 >= EINA_PATH_MAX)
2010-07-27 19:37:05 -07:00
continue;
}
while ((dp->d_name[0] == '.') &&
2010-07-27 19:37:05 -07:00
((dp->d_name[1] == '\0') ||
((dp->d_name[1] == '.') && (dp->d_name[2] == '\0'))));
memcpy(it->info.path + it->info.name_start, dp->d_name, length);
it->info.name_length = length;
it->info.path_length = it->info.name_start + length;
it->info.path[it->info.path_length] = '\0';
#ifdef _DIRENT_HAVE_D_TYPE
switch (dp->d_type)
{
case DT_FIFO:
it->info.type = EINA_FILE_FIFO;
break;
case DT_CHR:
it->info.type = EINA_FILE_CHR;
break;
case DT_DIR:
it->info.type = EINA_FILE_DIR;
break;
case DT_BLK:
it->info.type = EINA_FILE_BLK;
break;
case DT_REG:
it->info.type = EINA_FILE_REG;
break;
case DT_LNK:
it->info.type = EINA_FILE_LNK;
break;
case DT_SOCK:
it->info.type = EINA_FILE_SOCK;
break;
case DT_WHT:
it->info.type = EINA_FILE_WHT;
break;
default:
it->info.type = EINA_FILE_UNKNOWN;
break;
}
#else
it->info.type = EINA_FILE_UNKNOWN;
#endif
*data = &it->info;
return EINA_TRUE;
}
static DIR *
_eina_file_direct_ls_iterator_container(Eina_File_Direct_Iterator *it)
{
return it->dirp;
}
static void
_eina_file_direct_ls_iterator_free(Eina_File_Direct_Iterator *it)
{
closedir(it->dirp);
EINA_MAGIC_SET(&it->iterator, 0);
free(it);
}
static Eina_Bool
_eina_file_stat_ls_iterator_next(Eina_File_Direct_Iterator *it, void **data)
{
Eina_Stat st;
if (!_eina_file_direct_ls_iterator_next(it, data))
return EINA_FALSE;
if (it->info.type == EINA_FILE_UNKNOWN)
{
if (eina_file_statat(it->dirp, &it->info, &st) != 0)
it->info.type = EINA_FILE_UNKNOWN;
}
return EINA_TRUE;
}
#endif
void
eina_file_real_close(Eina_File *file)
{
2013-07-31 01:16:20 -07:00
Eina_File_Map *map;
EINA_LIST_FREE(file->dead_map, map)
{
munmap(map->map, map->length);
free(map);
}
if (file->fd != -1)
{
if (!file->copied && file->global_map != MAP_FAILED)
munmap(file->global_map, file->length);
close(file->fd);
}
}
static void
_eina_file_map_close(Eina_File_Map *map)
{
munmap(map->map, map->length);
free(map);
}
#ifndef MAP_POPULATE
static unsigned int
_eina_file_map_populate(char *map, unsigned long int size, Eina_Bool hugetlb)
{
unsigned int r = 0xDEADBEEF;
unsigned long int i;
unsigned int s;
if (size == 0) return 0;
s = hugetlb ? EINA_HUGE_PAGE : EINA_SMALL_PAGE;
for (i = 0; i < size; i += s)
r ^= map[i];
r ^= map[size - 1];
return r;
}
#endif
static char *
_page_aligned_address(const char *map, unsigned long int offset, Eina_Bool hugetlb)
{
const uintptr_t align = hugetlb ? EINA_HUGE_PAGE : EINA_SMALL_PAGE;
uintptr_t pmap = (uintptr_t) map;
pmap = (pmap + offset) - ((pmap + offset) & (align - 1));
return (char *) pmap;
}
static int
_eina_file_map_rule_apply(Eina_File_Populate rule, const void *map, unsigned long int offset,
unsigned long int size, unsigned long long maplen, Eina_Bool hugetlb)
{
int tmp = 42;
int flag = MADV_RANDOM;
char *addr;
switch (rule)
{
case EINA_FILE_RANDOM: flag = MADV_RANDOM; break;
case EINA_FILE_SEQUENTIAL: flag = MADV_SEQUENTIAL; break;
case EINA_FILE_POPULATE: flag = MADV_WILLNEED; break;
case EINA_FILE_WILLNEED: flag = MADV_WILLNEED; break;
2013-07-06 06:01:23 -07:00
case EINA_FILE_DONTNEED: flag = MADV_DONTNEED; break;
#ifdef MADV_REMOVE
2013-07-06 06:01:23 -07:00
case EINA_FILE_REMOVE: flag = MADV_REMOVE; break;
#elif defined (MADV_FREE)
case EINA_FILE_REMOVE: flag = MADV_FREE; break;
#else
# warning "EINA_FILE_REMOVE does not have system support"
#endif
2013-07-06 06:01:23 -07:00
default: return tmp; break;
}
if (offset >= maplen) return tmp;
// Align address, clamp size
addr = _page_aligned_address(map, offset, hugetlb);
if (size > 0)
{
size += ((char *) map + offset) - addr;
offset -= ((char *) map + offset) - addr;
if ((offset + size) > maplen)
{
if (offset > maplen) return tmp;
size = maplen - offset;
}
}
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);
}
/**
* @endcond
*/
/*============================================================================*
* Global *
*============================================================================*/
2013-07-31 01:16:20 -07:00
static Eina_Bool
_eina_file_mmap_faulty_one(void *addr, long page_size,
Eina_File_Map *m)
{
if ((unsigned char *) addr < (((unsigned char *)m->map) + m->length) &&
(((unsigned char *) addr) + page_size) >= (unsigned char *) m->map)
{
m->faulty = EINA_TRUE;
return EINA_TRUE;
}
return EINA_FALSE;
}
Eina_Bool
eina_file_mmap_faulty(void *addr, long page_size)
{
Eina_File_Map *m;
Eina_File *f;
Eina_Iterator *itf;
Eina_Iterator *itm;
Eina_Bool faulty = EINA_FALSE;
eina_lock_take(&_eina_file_lock_cache);
itf = eina_hash_iterator_data_new(_eina_file_cache);
EINA_ITERATOR_FOREACH(itf, f)
{
eina_lock_take(&f->lock);
if (f->global_map != MAP_FAILED)
{
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)
{
2013-07-31 01:16:20 -07:00
faulty = _eina_file_mmap_faulty_one(addr, page_size, m);
if (faulty) break;
}
eina_iterator_free(itm);
}
2013-07-31 01:16:20 -07:00
if (!faulty)
{
Eina_List *l;
EINA_LIST_FOREACH(f->dead_map, l, m)
{
faulty = _eina_file_mmap_faulty_one(addr, page_size, m);
if (faulty) break;
}
}
eina_lock_release(&f->lock);
if (faulty) break;
}
eina_iterator_free(itf);
eina_lock_release(&_eina_file_lock_cache);
return faulty;
}
/* ================================================================ *
* Simplified logic for portability layer with eina_file_common *
* ================================================================ */
2008-08-08 22:47:15 -07:00
Eina_Bool
eina_file_path_relative(const char *path)
{
if (*path != '/') return EINA_TRUE;
return EINA_FALSE;
}
Eina_Tmpstr *
eina_file_current_directory_get(const char *path, size_t len)
{
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);
return eina_tmpstr_add_length(tmp, len);
}
char *
eina_file_cleanup(Eina_Tmpstr *path)
{
char *result;
result = strdup(path ? path : "");
eina_tmpstr_del(path);
return result;
}
/*============================================================================*
* API *
*============================================================================*/
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Bool
2010-07-27 19:37:05 -07:00
eina_file_dir_list(const char *dir,
Eina_Bool recursive,
Eina_File_Dir_List_Cb cb,
void *data)
{
2011-03-22 09:33:34 -07:00
Eina_File_Direct_Info *info;
Eina_Iterator *it;
2010-07-27 19:37:05 -07:00
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);
2011-03-22 09:33:34 -07:00
it = eina_file_stat_ls(dir);
if (!it)
2010-07-27 19:37:05 -07:00
return EINA_FALSE;
2011-03-22 09:33:34 -07:00
EINA_ITERATOR_FOREACH(it, info)
2010-07-27 19:37:05 -07:00
{
2011-03-22 09:33:34 -07:00
cb(info->path + info->name_start, dir, data);
2011-03-22 09:33:34 -07:00
if (recursive == EINA_TRUE && info->type == EINA_FILE_DIR)
2010-07-27 19:37:05 -07:00
{
2011-03-22 09:33:34 -07:00
eina_file_dir_list(info->path, recursive, cb, data);
2010-07-27 19:37:05 -07:00
}
}
2011-03-22 09:33:34 -07:00
eina_iterator_free(it);
2010-07-27 19:37:05 -07:00
return EINA_TRUE;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Array *
eina_file_split(char *path)
{
2010-07-27 19:37:05 -07:00
Eina_Array *ea;
char *current;
size_t length;
2010-07-27 19:37:05 -07:00
EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
2010-07-27 19:37:05 -07:00
ea = eina_array_new(16);
2010-07-27 19:37:05 -07:00
if (!ea)
return NULL;
2010-07-27 19:37:05 -07:00
for (current = strchr(path, PATH_DELIM);
current;
2010-07-27 19:37:05 -07:00
path = current + 1, current = strchr(path, PATH_DELIM))
{
length = current - path;
if (length == 0)
2010-07-27 19:37:05 -07:00
continue;
2010-07-27 19:37:05 -07:00
eina_array_push(ea, path);
*current = '\0';
}
2010-07-27 19:37:05 -07:00
if (*path != '\0')
eina_array_push(ea, path);
2010-07-27 19:37:05 -07:00
return ea;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Iterator *
eina_file_ls(const char *dir)
{
#ifdef HAVE_DIRENT_H
Eina_File_Iterator *it;
size_t length;
DIR *dirp;
EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
length = strlen(dir);
2010-07-27 19:37:05 -07:00
if (length < 1)
return NULL;
dirp = opendir(dir);
if (!dirp)
2010-07-27 19:37:05 -07:00
return NULL;
it = calloc(1, sizeof (Eina_File_Iterator) + length);
if (EINA_UNLIKELY(!it))
{
closedir(dirp);
2010-07-27 19:37:05 -07:00
return NULL;
}
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->dirp = dirp;
memcpy(it->dir, dir, length + 1);
if (dir[length - 1] != '/')
2010-07-27 19:37:05 -07:00
it->length = length;
else
2010-07-27 19:37:05 -07:00
it->length = length - 1;
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_ls_iterator_next);
2010-07-27 19:37:05 -07:00
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
_eina_file_ls_iterator_container);
it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_ls_iterator_free);
return &it->iterator;
#else
(void) dir;
return NULL;
#endif
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Iterator *
eina_file_direct_ls(const char *dir)
{
#ifdef HAVE_DIRENT_H
Eina_File_Direct_Iterator *it;
size_t length;
DIR *dirp;
EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
length = strlen(dir);
2010-07-27 19:37:05 -07:00
if (length < 1)
return NULL;
dirp = opendir(dir);
if (!dirp)
2010-07-27 19:37:05 -07:00
return NULL;
it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
if (EINA_UNLIKELY(!it))
{
closedir(dirp);
2010-07-27 19:37:05 -07:00
return NULL;
}
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->dirp = dirp;
if (length + _eina_name_max(it->dirp) + 2 >= EINA_PATH_MAX)
{
_eina_file_direct_ls_iterator_free(it);
return NULL;
}
2010-07-27 19:37:05 -07:00
memcpy(it->dir, dir, length + 1);
it->length = length;
memcpy(it->info.path, dir, length);
if (dir[length - 1] == '/')
2010-07-27 19:37:05 -07:00
it->info.name_start = length;
else
{
2010-07-27 19:37:05 -07:00
it->info.path[length] = '/';
it->info.name_start = length + 1;
}
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_direct_ls_iterator_next);
2010-07-27 19:37:05 -07:00
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
_eina_file_direct_ls_iterator_container);
it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
return &it->iterator;
#else
(void) dir;
return NULL;
#endif
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Iterator *
eina_file_stat_ls(const char *dir)
{
#ifdef HAVE_DIRENT_H
Eina_File_Direct_Iterator *it;
size_t length;
DIR *dirp;
EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL);
length = strlen(dir);
if (length < 1)
return NULL;
dirp = opendir(dir);
if (!dirp)
return NULL;
it = calloc(1, sizeof(Eina_File_Direct_Iterator) + length);
if (EINA_UNLIKELY(!it))
2012-10-19 01:18:59 -07:00
{
closedir(dirp);
return NULL;
}
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
it->dirp = dirp;
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;
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;
}
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(_eina_file_stat_ls_iterator_next);
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
_eina_file_direct_ls_iterator_container);
it->iterator.free = FUNC_ITERATOR_FREE(_eina_file_direct_ls_iterator_free);
return &it->iterator;
#else
(void) dir;
return NULL;
#endif
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_File *
eina_file_open(const char *path, Eina_Bool shared)
{
Eina_File *file;
Eina_File *n;
Eina_Stringshare *filename;
struct stat file_stat;
int fd = -1;
Eina_Statgen statgen;
EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL);
filename = eina_file_sanitize(path);
if (!filename) return NULL;
statgen = eina_file_statgen_get();
eina_lock_take(&_eina_file_lock_cache);
file = eina_hash_find(_eina_file_cache, filename);
statgen = eina_file_statgen_get();
if ((!file) || (file->statgen != statgen) || (statgen == 0))
{
if (shared)
{
#ifdef HAVE_SHM_OPEN
fd = shm_open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if ((fd != -1) && (!eina_file_close_on_exec(fd, EINA_TRUE)))
goto on_error;
#else
goto on_error;
#endif
}
else
{
#ifdef HAVE_OPEN_CLOEXEC
fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO | O_CLOEXEC);
#else
fd = open(filename, O_RDONLY, S_IRWXU | S_IRWXG | S_IRWXO);
if ((fd != -1) && (!eina_file_close_on_exec(fd, EINA_TRUE)))
goto on_error;
#endif
}
if (fd < 0) goto on_error;
if (fstat(fd, &file_stat))
goto on_error;
if (file) file->statgen = statgen;
if ((file) && !_eina_file_timestamp_compare(file, &file_stat))
{
file->delete_me = EINA_TRUE;
eina_hash_del(_eina_file_cache, file->filename, file);
file = NULL;
}
}
if (!file)
{
n = malloc(sizeof(Eina_File));
if (!n)
goto on_error;
memset(n, 0, sizeof(Eina_File));
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->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->fd = fd;
n->shared = shared;
eina_lock_new(&n->lock);
eina_hash_direct_add(_eina_file_cache, n->filename, n);
EINA_MAGIC_SET(n, EINA_FILE_MAGIC);
}
else
{
if (fd >= 0) close(fd);
n = file;
}
eina_lock_take(&n->lock);
n->refcount++;
eina_lock_release(&n->lock);
eina_lock_release(&_eina_file_lock_cache);
return n;
on_error:
eina_lock_release(&_eina_file_lock_cache);
INF("Could not open file [%s].", filename);
eina_stringshare_del(filename);
if (fd >= 0) close(fd);
return NULL;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Bool
2013-07-31 01:16:20 -07:00
eina_file_refresh(Eina_File *file)
{
struct stat file_stat;
Eina_Bool r = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
if (file->virtual) return EINA_FALSE;
if (fstat(file->fd, &file_stat))
return EINA_FALSE;
if (file->length != (unsigned long int) file_stat.st_size)
{
eina_file_flush(file, file_stat.st_size);
r = EINA_TRUE;
}
file->length = file_stat.st_size;
file->mtime = file_stat.st_mtime;
#ifdef _STAT_VER_LINUX
# if (defined __USE_MISC && defined st_mtime)
file->mtime_nsec = (unsigned long int)file_stat.st_mtim.tv_nsec;
# else
file->mtime_nsec = (unsigned long int)file_stat.st_mtimensec;
# endif
#endif
file->inode = file_stat.st_ino;
return r;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Bool
eina_file_unlink(const char *pathname)
{
if ( unlink(pathname) < 0)
{
return EINA_FALSE;
}
return EINA_TRUE;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API void *
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);
if (file->virtual) return eina_file_virtual_map_all(file);
// bsd people will lack this feature
#ifdef MAP_POPULATE
if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
2011-04-21 04:54:16 -07:00
#endif
#ifdef MAP_HUGETLB
if (file->length >= EINA_HUGE_PAGE_MIN) 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_Bool hugetlb = EINA_FALSE;
#ifdef MAP_HUGETLB
hugetlb = !!(flags & MAP_HUGETLB);
#endif
if (!file->global_refcount)
file->global_hugetlb = hugetlb;
else
hugetlb = file->global_hugetlb;
_eina_file_map_rule_apply(rule, file->global_map, 0, file->length, file->length, hugetlb);
file->global_refcount++;
ret = file->global_map;
}
eina_lock_release(&file->lock);
return ret;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API 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);
if (file->virtual)
return eina_file_virtual_map_new(file, offset, 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;
2011-04-21 04:54:16 -07:00
// bsd people will lack this feature
#ifdef MAP_POPULATE
if (rule == EINA_FILE_POPULATE) flags |= MAP_POPULATE;
2011-04-21 04:54:16 -07:00
#endif
#ifdef MAP_HUGETLB
if (length >= EINA_HUGE_PAGE_MIN) flags |= MAP_HUGETLB;
#endif
map = malloc(sizeof (Eina_File_Map));
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) 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, 0, length, map->length, map->hugetlb);
eina_lock_release(&file->lock);
return map->map;
on_error:
free(map);
eina_lock_release(&file->lock);
return NULL;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API void
eina_file_map_free(Eina_File *file, void *map)
{
EINA_SAFETY_ON_NULL_RETURN(file);
if (file->virtual)
2014-07-13 03:44:34 -07:00
{
eina_file_virtual_map_free(file, map);
return;
}
eina_lock_take(&file->lock);
if (file->global_map == map)
{
file->global_refcount--;
if (file->global_refcount > 0) goto on_exit;
munmap(file->global_map, file->length);
file->global_map = MAP_FAILED;
}
else
{
2013-07-31 01:16:20 -07:00
eina_file_common_map_free(file, map, _eina_file_map_close);
}
on_exit:
eina_lock_release(&file->lock);
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API void
eina_file_map_populate(Eina_File *file, Eina_File_Populate rule, const void *map,
2013-07-06 06:01:23 -07:00
unsigned long int offset, unsigned long int length)
{
Eina_File_Map *em;
2013-07-06 06:01:23 -07:00
EINA_SAFETY_ON_NULL_RETURN(file);
eina_lock_take(&file->lock);
if (map == file->global_map)
_eina_file_map_rule_apply(rule, map, offset, length, file->length, file->global_hugetlb);
else if ((em = eina_hash_find(file->rmap, &map)) != NULL)
_eina_file_map_rule_apply(rule, map, offset, length, em->length, em->hugetlb);
2013-07-06 06:01:23 -07:00
eina_lock_release(&file->lock);
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Bool
eina_file_map_faulted(Eina_File *file, void *map)
{
Eina_Bool r = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(file, EINA_FALSE);
if (file->virtual) return EINA_FALSE;
eina_lock_take(&file->lock);
if (file->global_map == map)
{
r = file->global_faulty;
}
else
{
2013-07-31 01:16:20 -07:00
Eina_File_Map *em;
em = eina_hash_find(file->rmap, &map);
2013-07-31 01:16:20 -07:00
if (em)
{
r = em->faulty;
}
else
{
Eina_List *l;
EINA_LIST_FOREACH(file->dead_map, l, em)
if (em->map == map)
{
r = em->faulty;
break;
}
}
}
eina_lock_release(&file->lock);
return r;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Iterator *
eina_file_xattr_get(Eina_File *file)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
if (file->virtual) return NULL;
return eina_xattr_fd_ls(file->fd);
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Iterator *
eina_file_xattr_value_get(Eina_File *file)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL);
if (file->virtual) return NULL;
return eina_xattr_value_fd_ls(file->fd);
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API int
eina_file_statat(void *container, Eina_File_Direct_Info *info, Eina_Stat *st)
{
struct stat buf;
#ifdef HAVE_ATFILE_SOURCE
int fd;
#endif
EINA_SAFETY_ON_NULL_RETURN_VAL(info, -1);
EINA_SAFETY_ON_NULL_RETURN_VAL(st, -1);
#ifdef HAVE_ATFILE_SOURCE
fd = dirfd((DIR*) container);
if (fstatat(fd, info->path + info->name_start, &buf, 0))
#else
2012-03-07 11:52:21 -08:00
(void)container;
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;
}
///////////////////////////////////////////////////////////////////////////
// this below is funky avoiding opendir to avoid heap allocations thus
// getdents and all the os specific stuff as this is intendedf for use
// between fork and exec normally ... this is important
#if defined(__FreeBSD__)
# define do_getdents(fd, buf, size) getdents(fd, buf, size)
typedef struct
{
#if __FreeBSD__ > 11
ino_t d_ino;
off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
unsigned char ____pad0;
unsigned short d_namlen;
unsigned short ____pad1;
char d_name[4096];
#else
__uint32_t d_fileno;
__uint16_t d_reclen;
__uint8_t d_type;
__uint8_t d_namlen;
char d_name[4096];
#endif
} Dirent;
#elif defined(__OpenBSD__)
# define do_getdents(fd, buf, size) getdents(fd, buf, size)
typedef struct
{
__ino_t d_ino;
__off_t d_off;
unsigned short d_reclen;
unsigned char d_type;
unsigned char d_namlen;
unsigned char ____pad[4];
char d_name[4096];
} Dirent;
#elif defined(__linux__)
# define do_getdents(fd, buf, size) syscall(SYS_getdents64, fd, buf, size)
// getdents64 added un glibc 2.30 ... so use raw syscall - will work
// from some linux 2.4 on... so ... i think that's ok. :)
//# define do_getdents(fd, buf, size) getdents64(fd, buf, size)
typedef struct
{
ino64_t d_ino;
off64_t d_off;
unsigned short d_reclen;
unsigned char d_type;
char d_name[4096];
} Dirent;
#endif
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API void
eina_file_close_from(int fd, int *except_fd)
{
#if defined(_WIN32)
// XXX: what do to here? anything?
#else
#ifdef HAVE_DIRENT_H
//# if 0
# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__linux__)
int dirfd;
Dirent *d;
char buf[4096];
int *closes = NULL;
int num_closes = 0, i, j, clo, num;
const char *fname;
ssize_t pos, ret;
Eina_Bool do_read;
// note - this api is EXPECTED to be called in between a fork() and exec()
// when no threads are running. if you use this outside that context then
// it may not work as intended and may miss some fd's etc.
dirfd = open("/proc/self/fd", O_RDONLY | O_DIRECTORY);
if (dirfd < 0) dirfd = open("/dev/fd", O_RDONLY | O_DIRECTORY);
if (dirfd >= 0)
{
// count # of closes - the dir list should/will not change as its
// the fd's we have open so we can read it twice with no changes
// to it
do_read = EINA_TRUE;
for (;;)
{
skip:
if (do_read)
{
pos = 0;
ret = do_getdents(dirfd, buf, sizeof(buf));
if (ret <= 0) break;
do_read = EINA_FALSE;
}
d = (Dirent *)(buf + pos);
fname = d->d_name;
pos += d->d_reclen;
if (pos >= ret) do_read = EINA_TRUE;
if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
num = atoi(fname);
if (num < fd) continue;
if (except_fd)
{
for (j = 0; except_fd[j] >= 0; j++)
{
if (except_fd[j] == num) goto skip;
}
}
num_closes++;
}
// alloc closes list and walk again to fill it - on stack to avoid
// heap allocs
closes = alloca(num_closes * sizeof(int));
if ((closes) && (num_closes > 0))
{
clo = 0;
lseek(dirfd, 0, SEEK_SET);
do_read = EINA_TRUE;
for (;;)
{
skip2:
if (do_read)
{
pos = 0;
ret = do_getdents(dirfd, buf, sizeof(buf));
if (ret <= 0) break;
do_read = EINA_FALSE;
}
d = (Dirent *)(buf + pos);
fname = d->d_name;
pos += d->d_reclen;
if (pos >= ret) do_read = EINA_TRUE;
if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
num = atoi(fname);
if (num < fd) continue;
if (except_fd)
{
for (j = 0; except_fd[j] >= 0; j++)
{
if (except_fd[j] == num) goto skip2;
}
}
if (clo < num_closes) closes[clo] = num;
clo++;
}
// in case we somehow don't fill up all of closes in 2nd pass
// (this shouldn't happen as no threads are running and we
// do nothing to modify the fd set between 2st and 2nd pass).
// set rest num_closes to clo so we don't close invalid values
num_closes = clo;
}
close(dirfd);
// now go close all those fd's - some may be invalide like the dir
// reading fd above... that's ok.
for (i = 0; i < num_closes; i++)
{
close(closes[i]);
}
return;
}
# else
DIR *dir;
int *closes = NULL;
int num_closes = 0, i, j, clo, num;
struct dirent *dp;
const char *fname;
dir = opendir("/proc/self/fd");
if (!dir) dir = opendir("/dev/fd");
if (dir)
{
// count # of closes - the dir list should/will not change as its
// the fd's we have open so we can read it twice with no changes
// to it
for (;;)
{
skip:
if (!(dp = readdir(dir))) break;
fname = dp->d_name;
if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
num = atoi(fname);
if (num < fd) continue;
if (except_fd)
{
for (j = 0; except_fd[j] >= 0; j++)
{
if (except_fd[j] == num) goto skip;
}
}
num_closes++;
}
// alloc closes list and walk again to fill it - on stack to avoid
// heap allocs
closes = alloca(num_closes * sizeof(int));
if ((closes) && (num_closes > 0))
{
clo = 0;
seekdir(dir, 0);
for (;;)
{
skip2:
if (!(dp = readdir(dir))) break;
fname = dp->d_name;
if (!((fname[0] >= '0') && (fname[0] <= '9'))) continue;
num = atoi(fname);
if (num < fd) continue;
if (except_fd)
{
for (j = 0; except_fd[j] >= 0; j++)
{
if (except_fd[j] == num) goto skip2;
}
}
if (clo < num_closes) closes[clo] = num;
clo++;
}
}
closedir(dir);
// now go close all those fd's - some may be invalide like the dir
// reading fd above... that's ok.
for (i = 0; i < num_closes; i++)
{
close(closes[i]);
}
return;
}
# endif
#endif
int max = 1024;
#ifdef HAVE_SYS_RESOURCE_H
struct rlimit lim;
if (getrlimit(RLIMIT_NOFILE, &lim) < 0) return;
max = lim.rlim_max;
#endif
for (i = fd; i < max;)
{
if (except_fd)
{
int j;
for (j = 0; except_fd[j] >= 0; j++)
{
if (except_fd[j] == i) goto skip3;
}
}
close(i);
skip3:
i++;
}
#endif
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API int
eina_file_mkstemp(const char *templatename, Eina_Tmpstr **path)
{
char buffer[PATH_MAX];
const char *XXXXXX = NULL, *sep;
int fd, len;
mode_t old_umask;
EINA_SAFETY_ON_NULL_RETURN_VAL(templatename, -1);
sep = strchr(templatename, '/');
if (sep)
{
len = eina_strlcpy(buffer, templatename, sizeof(buffer));
}
else
{
len = eina_file_path_join(buffer, sizeof(buffer),
eina_environment_tmp_get(), templatename);
}
/*
* Unix:
* Make sure temp file is created with secure permissions,
* http://man7.org/linux/man-pages/man3/mkstemp.3.html#NOTES
*/
old_umask = umask(S_IRWXG|S_IRWXO);
if ((XXXXXX = strstr(buffer, "XXXXXX.")) != NULL)
{
int suffixlen = buffer + len - XXXXXX - 6;
fd = mkstemps(buffer, suffixlen);
}
else
fd = mkstemp(buffer);
umask(old_umask);
if (fd < 0)
{
if (path) *path = NULL;
return -1;
}
if (path) *path = eina_tmpstr_add(buffer);
return fd;
}
eina: Rename EAPI macro to EINA_API in Eina library Summary: Patch from a series of patches to rename EAPI symbols to specific library DSOs. EAPI was designed to be able to pass `__attribute__ ((visibility ("default")))` for symbols with GCC, which would mean that even if -fvisibility=hidden was used when compiling the library, the needed symbols would get exported. MSVC __almost__ works like GCC (or mingw) in which you can declare everything as export and it will just work (slower, but it will work). But there's a caveat: global variables will not work the same way for MSVC, but works for mingw and GCC. For global variables (as opposed to functions), MSVC requires correct DSO visibility for MSVC: instead of declaring a symbol as export for everything, you need to declare it as import when importing from another DSO and export when defining it locally. With current EAPI definitions, we get the following example working in mingw and MSVC (observe it doesn't define any global variables as exported symbols). Example 1: dll1: ``` EAPI void foo(void); EAPI void bar() { foo(); } ``` dll2: ``` EAPI void foo() { printf ("foo\n"); } ``` This works fine with API defined as __declspec(dllexport) in both cases and for gcc defining as `__atttribute__((visibility("default")))` However, the following: Example 2: dll1: ``` EAPI extern int foo; EAPI void foobar(void); EAPI void bar() { foo = 5; foobar(); } ``` dll2: ``` EAPI int foo = 0; EAPI void foobar() { printf ("foo %d\n", foo); } ``` This will work on mingw but will not work for MSVC. And that's why EAPI is the only solution that worked for MSVC. Co-authored-by: João Paulo Taylor Ienczak Zanette <jpaulotiz@gmail.com> Co-authored-by: Ricardo Campos <ricardo.campos@expertise.dev> Co-authored-by: Lucas Cavalcante de Sousa <lucks.sousa@gmail.com> Reviewers: jptiz, lucas, woohyun, vtorri, raster Reviewed By: jptiz, lucas, vtorri Subscribers: ProhtMeyhet, cedric, #reviewers, #committers Tags: #efl Differential Revision: https://phab.enlightenment.org/D12188
2020-11-25 04:35:48 -08:00
EINA_API Eina_Bool
eina_file_mkdtemp(const char *templatename, Eina_Tmpstr **path)
{
char buffer[PATH_MAX];
char *tmpdirname, *sep;
EINA_SAFETY_ON_NULL_RETURN_VAL(templatename, EINA_FALSE);
sep = strchr(templatename, '/');
if (sep)
{
eina_strlcpy(buffer, templatename, sizeof(buffer));
}
else
{
eina_file_path_join(buffer, sizeof(buffer),
eina_environment_tmp_get(), templatename);
}
tmpdirname = mkdtemp(buffer);
if (tmpdirname == NULL)
{
if (path) *path = NULL;
return EINA_FALSE;
}
if (path) *path = eina_tmpstr_add(tmpdirname);
return EINA_TRUE;
}