Compare commits

...

2 Commits

Author SHA1 Message Date
Lauro Moura e2dcc136b3 Adds Eo-based Eio api and moves the current Eio to legacy.
The legacy Eio_File factory functions are replaced by an Eo object
called Eo_Job that return promises wrapping the async file operations.
With this commit, the legacy Eio callbacks are replaced by the following
Eo/Promises counterparts :

* Done_Cb -> Promise then success callback
* Error_Cb -> Promise then error callback
* Main_Cb -> Promise progress callback
* Filter_Cb -> Job object event (more below)

Events are used to deliver and get the filter data. To differentiate
between the named and direct versions, they come in "filter,direct" and
"filter,name" versions.

Monitors were wrapped inside a new class Eo_Sentry.

The user creates a sentry object and adds monitoring targets to it,
listening to events on it.

The sentry event info is composed of two strings. The source string
is the path being monitored, i.e. the one passed to eio_sentry_add, and
the trigger string is the path that actually triggered the event, e.g.
a new file created in a monitored directory.

Eina mmap and Eet-related functions are not (yet?) supported.
2016-05-23 21:15:02 -03:00
Lauro Moura 1775fe1876 eio: Call correct function to cleanup Eio_File.
The Eio functions operating on Eina_Files were just freeing
the Eio_File pointer on completion instead of calling eio_file_free
to unregister the thread.
2016-05-23 16:29:33 -03:00
26 changed files with 4045 additions and 1358 deletions

View File

@ -2,7 +2,9 @@
### Library
eio_eolian_files = \
lib/eio/eio_model.eo
lib/eio/eio_model.eo \
lib/eio/eio_job.eo \
lib/eio/eio_sentry.eo
eio_eolian_h = $(eio_eolian_files:%.eo=%.eo.h)
eio_eolian_c = $(eio_eolian_files:%.eo=%.eo.c)
@ -20,13 +22,19 @@ lib/eio/Makefile.in
installed_eiomainheadersdir = $(includedir)/eio-@VMAJ@
dist_installed_eiomainheaders_DATA = lib/eio/Eio.h lib/eio/eio_inline_helper.x
dist_installed_eiomainheaders_DATA = \
lib/eio/Eio.h \
lib/eio/Eio_Legacy.h \
lib/eio/Eio_Eo.h \
lib/eio/eio_inline_helper.x
nodist_installed_eiomainheaders_DATA = $(eio_eoolian_h)
lib_eio_libeio_la_SOURCES = \
lib/eio/eio_dir.c \
lib/eio/eio_eet.c \
lib/eio/eio_file.c \
lib/eio/eio_job.c \
lib/eio/eio_sentry.c \
lib/eio/eio_main.c \
lib/eio/eio_map.c \
lib/eio/eio_monitor.c \
@ -62,13 +70,6 @@ if HAVE_NOTIFY_COCOA
lib_eio_libeio_la_LDFLAGS += -framework CoreServices
endif
if HAVE_CXX11
eio_eolian_cxx_hh = $(eio_eolian_files:%.eo=%.eo.hh)
eio_eolian_cxx_impl = $(eio_eolian_files:%.eo=%.eo.impl.hh)
endif
if EFL_ENABLE_TESTS
check_PROGRAMS += tests/eio/eio_suite
@ -79,8 +80,13 @@ tests/eio/eio_suite.c \
tests/eio/eio_model_test_file.c \
tests/eio/eio_model_test_monitor_add.c \
tests/eio/eio_test_monitor.c \
tests/eio/eio_test_sentry.c \
tests/eio/eio_test_file.c \
tests/eio/eio_test_job.c \
tests/eio/eio_test_job_xattr.c \
tests/eio/eio_test_xattr.c \
tests/eio/eio_test_common.c \
tests/eio/eio_test_common.h \
tests/eio/eio_suite.h
tests_eio_eio_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \

View File

@ -24,31 +24,53 @@ endif
EXTRA_PROGRAMS = \
eio_file_ls \
eio_file_copy
eio_file_copy \
eio_job_open \
eio_job_open_multi \
eio_job_ls \
eio_sentry
EIO_EXAMPLES_LDADD = \
$(top_builddir)/src/lib/eio/libeio.la \
$(top_builddir)/src/lib/eo/libeo.la \
$(top_builddir)/src/lib/ecore/libecore.la \
$(top_builddir)/src/lib/efl/libefl.la \
$(top_builddir)/src/lib/eet/libeet.la \
$(top_builddir)/src/lib/emile/libemile.la \
$(top_builddir)/src/lib/eina/libeina.la \
@EIO_LDFLAGS@
eio_file_ls_SOURCES = eio_file_ls.c
eio_file_ls_LDADD = \
$(top_builddir)/src/lib/eio/libeio.la \
$(top_builddir)/src/lib/eo/libeo.la \
$(top_builddir)/src/lib/ecore/libecore.la \
$(top_builddir)/src/lib/eet/libeet.la \
$(top_builddir)/src/lib/emile/libemile.la \
$(top_builddir)/src/lib/eina/libeina.la \
@EIO_LDFLAGS@
$(EIO_EXAMPLES_LDADD)
eio_file_copy_SOURCES = eio_file_copy.c
eio_file_copy_LDADD = \
$(top_builddir)/src/lib/eio/libeio.la \
$(top_builddir)/src/lib/eo/libeo.la \
$(top_builddir)/src/lib/ecore/libecore.la \
$(top_builddir)/src/lib/eet/libeet.la \
$(top_builddir)/src/lib/emile/libemile.la \
$(top_builddir)/src/lib/eina/libeina.la \
@EIO_LDFLAGS@
$(EIO_EXAMPLES_LDADD)
eio_job_open_SOURCES = eio_job_open.c
eio_job_open_LDADD = \
$(EIO_EXAMPLES_LDADD)
eio_job_open_multi_SOURCES = eio_job_open_multi.c
eio_job_open_multi_LDADD = \
$(EIO_EXAMPLES_LDADD)
eio_job_ls_SOURCES = eio_job_ls.c
eio_job_ls_LDADD = \
$(EIO_EXAMPLES_LDADD)
eio_sentry_SOURCES = eio_sentry.c
eio_sentry_LDADD = \
$(EIO_EXAMPLES_LDADD)
SRCS = \
eio_file_ls.c \
eio_file_copy.c
eio_file_copy.c \
eio_job_open.c \
eio_job_open_multi.c \
eio_job_ls.c \
eio_sentry.c
DATA_FILES = Makefile.examples

View File

@ -0,0 +1,79 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <Eina.h>
#include <Eio.h>
#include <Ecore.h>
void done_cb(void *data, void *value EINA_UNUSED)
{
Eio_Job *job = data;
printf("%s done listing files.\n", __FUNCTION__);
ecore_main_loop_quit();
eo_unref(job);
}
void error_cb(void *data, Eina_Error *error)
{
Eio_Job *job = data;
EINA_SAFETY_ON_NULL_RETURN(error);
const char *msg = eina_error_msg_get(*error);
printf("%s error: %s\n", __FUNCTION__, msg);
ecore_main_loop_quit();
eo_unref(job);
}
void filter_cb(void *data, const Eo_Event *event)
{
Eio_Filter_Name_Data *event_info = event->info;
static Eina_Bool should_filter = EINA_FALSE;
printf("Filtering file %s\n", event_info->file);
should_filter = !should_filter;
event_info->filter = should_filter;
}
// Progress used to be the "Eio_Main_Cb" family of callbacks in the legacy API.
void progress_cb(void *data, const char *filename)
{
EINA_SAFETY_ON_NULL_RETURN(filename);
printf("%s listing filename: %s\n", __FUNCTION__, filename);
}
void list_files(void *data)
{
Eina_Promise *promise;
const char *path = data;
Eio_Job *job = eo_add(EIO_JOB_CLASS, NULL);
eo_event_callback_add(job, EIO_JOB_EVENT_FILTER_NAME, (Eo_Event_Cb)&filter_cb, NULL);
eio_job_file_ls(job, path, &promise);
eina_promise_progress_cb_add(promise, (Eina_Promise_Progress_Cb)&progress_cb, NULL, NULL);
eina_promise_then(promise, (Eina_Promise_Cb)&done_cb, (Eina_Promise_Error_Cb)&error_cb, job);
}
int main(int argc, char const *argv[])
{
eio_init();
ecore_init();
const char *path = getenv("HOME");
if (argc > 1)
path = argv[1];
Ecore_Job *job = ecore_job_add(&list_files, path);
ecore_main_loop_begin();
ecore_shutdown();
eio_shutdown();
return 0;
}

View File

@ -0,0 +1,80 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <Eina.h>
#include <Eio.h>
#include <Ecore.h>
void error_cb(void *data, Eina_Error *error)
{
EINA_SAFETY_ON_NULL_RETURN(error);
EINA_SAFETY_ON_NULL_RETURN(data);
const char *msg = eina_error_msg_get(*error);
EINA_LOG_ERR("error: %s", msg);
ecore_main_loop_quit();
}
void done_closing_cb(int *result EINA_UNUSED)
{
printf("%s closed file.\n", __FUNCTION__);
ecore_main_loop_quit();
}
void closing_job(Eio_Job *job, Eina_File *file)
{
Eina_Promise *promise = NULL;
printf("%s Will close the file...\n", __FUNCTION__);
eio_job_file_close(job, file, &promise);
eina_promise_then(promise, (Eina_Promise_Cb)&done_closing_cb, (Eina_Promise_Error_Cb)&error_cb, job);
}
void done_open_cb(void *data, Eina_File **file)
{
EINA_SAFETY_ON_NULL_RETURN(data);
EINA_SAFETY_ON_NULL_RETURN(file);
EINA_SAFETY_ON_NULL_RETURN(*file);
Eio_Job *job = data;
const char *name = eina_file_filename_get(*file);
printf("%s opened file %s\n", __FUNCTION__, name);
closing_job(job, *file);
}
void open_file(const char *path)
{
Eina_Promise *promise;
Eio_Job *job = eo_add(EIO_JOB_CLASS, NULL);
eio_job_file_open(job, path, EINA_FALSE, &promise);
eina_promise_then(promise, (Eina_Promise_Cb)&done_open_cb, (Eina_Promise_Error_Cb)&error_cb, job);
eo_unref(job);
}
int main(int argc, char const *argv[])
{
eio_init();
ecore_init();
const char *path = getenv("HOME");
if (argc > 1)
path = argv[1];
open_file(path);
ecore_main_loop_begin();
ecore_shutdown();
eio_shutdown();
return 0;
}

View File

@ -0,0 +1,103 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <Eina.h>
#include <Eio.h>
#include <Ecore.h>
void error_cb(void *data, Eina_Error *error)
{
EINA_SAFETY_ON_NULL_RETURN(error);
EINA_SAFETY_ON_NULL_RETURN(data);
const char *msg = eina_error_msg_get(*error);
EINA_LOG_ERR("error: %s", msg);
Eio_Job *job = data;
eo_unref(job);
ecore_main_loop_quit();
}
void done_closing_cb(void *data, Eina_Iterator **result EINA_UNUSED)
{
EINA_SAFETY_ON_NULL_RETURN(data);
printf("%s closed file.\n", __FUNCTION__);
Eio_Job *job = data;
eo_unref(job);
ecore_main_loop_quit();
}
void closing_job(Eio_Job *job, Eina_File *file1, Eina_File *file2)
{
Eina_Promise *promise;
Eina_Promise *tasks[3] = {NULL, NULL, NULL};
printf("%s Closing files.\n", __FUNCTION__);
eio_job_file_close(job, file1, &tasks[0]);
eio_job_file_close(job, file2, &tasks[1]);
promise = eina_promise_all(eina_carray_iterator_new((void**)&tasks[0]));
eina_promise_then(promise, (Eina_Promise_Cb)&done_closing_cb, (Eina_Promise_Error_Cb)&error_cb, job);
}
void done_open_cb(void *data, Eina_Iterator **iterator)
{
EINA_SAFETY_ON_NULL_RETURN(data);
EINA_SAFETY_ON_NULL_RETURN(iterator);
EINA_SAFETY_ON_NULL_RETURN(*iterator);
Eio_Job *job = data;
Eina_File **file = NULL;
Eina_File **files = calloc(sizeof(Eina_File*),2);
int i = 0;
while (eina_iterator_next(*iterator, (void**)&file))
{
files[i] = *file;
const char *name = eina_file_filename_get(*file);
printf("%s opened file %s\n", __FUNCTION__, name);
i++;
}
closing_job(job, files[0], files[1]);
free(files);
}
void open_file(const char *path, const char *path2)
{
Eina_Promise *promise;
Eina_Promise *tasks[3] = {NULL, NULL, NULL};
Eio_Job *job = eo_add(EIO_JOB_CLASS, NULL);
eio_job_file_open(job, path, EINA_FALSE, &tasks[0]);
eio_job_file_open(job, path2, EINA_FALSE, &tasks[1]);
promise = eina_promise_all(eina_carray_iterator_new((void**)&tasks[0]));
eina_promise_then(promise, (Eina_Promise_Cb)&done_open_cb, (Eina_Promise_Error_Cb)&error_cb, job);
}
int main(int argc, char const *argv[])
{
eio_init();
ecore_init();
const char *path = getenv("HOME");
const char *path2 = "./";
if (argc > 1)
path = argv[1];
if (argc > 2)
path2 = argv[2];
open_file(path, path2);
ecore_main_loop_begin();
ecore_shutdown();
eio_shutdown();
return 0;
}

View File

@ -0,0 +1,55 @@
#if HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdlib.h>
#include <stdio.h>
#include <Eina.h>
#include <Eio.h>
#include <Ecore.h>
Eina_Bool
sentry_cb(void *data, const Eo_Event *event)
{
Eio_Sentry_Event *event_info = event->info;
printf("Event on monitored path %s", event_info->source);
printf("Created file %s\n", event_info->trigger);
ecore_main_loop_quit();
return EINA_FALSE;
}
void
monitor_stuff(void *data)
{
const char *path = data;
Eio_Sentry *sentry = eo_add(EIO_SENTRY_CLASS, NULL);
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_CREATED, (Eo_Event_Cb)&sentry_cb, NULL);
printf("Starting monitoring path %s\n", path);
eio_sentry_add(sentry, path);
}
int
main(int argc, char const *argv[])
{
eio_init();
ecore_init();
const char *path = getenv("HOME");
if (argc > 1)
path = argv[1];
Ecore_Job *job = ecore_job_add(&monitor_stuff, path);
ecore_main_loop_begin();
ecore_shutdown();
eio_shutdown();
return 0;
}

File diff suppressed because it is too large Load Diff

13
src/lib/eio/Eio_Eo.h Normal file
View File

@ -0,0 +1,13 @@
/* This include has been added to support Eo in Eio */
#include <Eo.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "eio_job.eo.h"
#include "eio_sentry.eo.h"
#ifdef __cplusplus
}
#endif

1256
src/lib/eio/Eio_Legacy.h Normal file

File diff suppressed because it is too large Load Diff

586
src/lib/eio/eio_job.c Normal file
View File

@ -0,0 +1,586 @@
/* EIO - EFL data type library
* Copyright (C) 2016 Enlightenment Developers:
* Lauro Moura <lauromoura@expertisesolutions.com.br>
*
* 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
#include <Eo.h>
#include "Eio.h"
#include "eio_job_private.h"
typedef Eio_File* (*Eio_Job_Direct_Ls_Func)(const char *path, Eio_Filter_Direct_Cb, Eio_Main_Direct_Cb, Eio_Done_Cb, Eio_Error_Cb, const void *data);
typedef struct _Job_Closure Job_Closure;
struct _Job_Closure
{
Eo *object;
Eio_Job_Data *pdata;
Eina_Promise_Owner *promise;
Eio_File *file;
Eina_Bool delete_me;
void *delayed_arg;
Eio_Job_Direct_Ls_Func direct_func; // Used when dispatching direct ls funcs.
};
/* Helper functions */
static Job_Closure *
_job_closure_create(Eo *obj, Eio_Job_Data *pdata, Eina_Promise_Owner *owner)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(obj, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(pdata, NULL);
EINA_SAFETY_ON_NULL_RETURN_VAL(owner, NULL);
Job_Closure *closure = malloc(sizeof(Job_Closure));
if (!closure)
{
EINA_LOG_CRIT("Failed to allocate memory.");
return 0;
}
closure->object = eo_ref(obj);
closure->pdata = pdata;
closure->promise = owner;
closure->file = NULL; // Will be set once the Eio operation is under way
closure->delete_me = EINA_FALSE;
closure->delayed_arg = NULL;
closure->direct_func = NULL;
pdata->operations = eina_list_prepend(pdata->operations, closure);
return closure;
}
static void
_job_closure_del(Job_Closure *closure)
{
EINA_SAFETY_ON_NULL_RETURN(closure);
Eio_Job_Data *pdata = closure->pdata;
if (pdata)
pdata->operations = eina_list_remove(pdata->operations, closure);
eo_unref(closure->object);
if (closure->delayed_arg)
free(closure->delayed_arg);
free(closure);
}
static void
_file_error_cb(void *data, Eio_File *handler EINA_UNUSED, int error)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN(operation);
EINA_SAFETY_ON_NULL_RETURN(operation->promise);
eina_promise_owner_error_set(operation->promise, error);
_job_closure_del(operation);
}
/* Basic listing callbacks */
static Eina_Bool
_file_ls_filter_cb_helper(const Eo_Event_Description *event, void *data, const char *file)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN_VAL(operation, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(operation->pdata, EINA_FALSE);
Eio_Filter_Name_Data* event_info = malloc(sizeof(Eio_Filter_Name_Data));
EINA_SAFETY_ON_NULL_RETURN_VAL(event_info, EINA_FALSE);
event_info->file = file;
event_info->filter = EINA_FALSE;
eo_event_callback_call(operation->pdata->object, event, event_info);
Eina_Bool filter = event_info->filter;
free(event_info);
return filter;
}
static Eina_Bool
_file_ls_filter_xattr_cb(void *data, Eio_File *handler EINA_UNUSED, const char *file)
{
return _file_ls_filter_cb_helper(EIO_JOB_EVENT_XATTR, data, file);
}
static Eina_Bool
_file_ls_filter_named_cb(void *data, Eio_File *handler EINA_UNUSED, const char *file)
{
return _file_ls_filter_cb_helper(EIO_JOB_EVENT_FILTER_NAME, data, file);
}
static void
_file_ls_main_cb(void *data, Eio_File *handler EINA_UNUSED, const char *file)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN(operation);
EINA_SAFETY_ON_NULL_RETURN(operation->promise);
eina_promise_owner_progress(operation->promise, (void*)file);
}
static void
_file_done_cb(void *data, Eio_File *handler EINA_UNUSED)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN(operation);
EINA_SAFETY_ON_NULL_RETURN(operation->promise);
// Placeholder value. We just want the callback to be called.
Eina_Bool result = EINA_TRUE;
eina_promise_owner_value_set(operation->promise, &result, NULL);
_job_closure_del(operation);
}
static void
_free_xattr_data(Eio_Xattr_Data *value)
{
EINA_SAFETY_ON_NULL_RETURN(value);
if (value->data)
free((void*)value->data);
}
static void
_file_done_data_cb(void *data, Eio_File *handler EINA_UNUSED, const char *attr_data, unsigned int size)
{
Job_Closure *operation = data;
Eio_Xattr_Data *ret_data = NULL;
EINA_SAFETY_ON_NULL_RETURN(operation);
EINA_SAFETY_ON_NULL_RETURN(operation->promise);
ret_data = malloc(sizeof(Eio_Xattr_Data));
if (!ret_data)
{
EINA_LOG_CRIT("Failed to create promise result data.");
return;
}
ret_data->data = calloc(sizeof(char), size + 1);
strcpy((char*)ret_data->data, attr_data);
ret_data->size = size;
eina_promise_owner_value_set(operation->promise, ret_data, (Eina_Promise_Free_Cb)&_free_xattr_data);
free(ret_data);
_job_closure_del(operation);
}
/* Direct listing callbacks */
static Eina_Bool
_file_direct_ls_filter_cb(void *data, Eio_File *handle EINA_UNUSED, const Eina_File_Direct_Info *info)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN_VAL(operation, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(operation->pdata, EINA_FALSE);
Eio_Filter_Direct_Data* event_info = malloc(sizeof(Eio_Filter_Direct_Data));
EINA_SAFETY_ON_NULL_RETURN_VAL(event_info, EINA_FALSE);
event_info->info = info;
event_info->filter = EINA_FALSE;
eo_event_callback_call(operation->pdata->object, EIO_JOB_EVENT_FILTER_DIRECT, event_info);
Eina_Bool filter = event_info->filter;
free(event_info);
return filter;
}
static void
_file_direct_ls_main_cb(void *data, Eio_File *handler EINA_UNUSED, const Eina_File_Direct_Info *info)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN(operation);
EINA_SAFETY_ON_NULL_RETURN(operation->promise);
eina_promise_owner_progress(operation->promise, (void*)info);
}
static void
_ls_direct_notify_start(void* data, Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = (Job_Closure*)data;
char* path = operation_data->delayed_arg;
Eio_File *handle = operation_data->direct_func(path,
_file_direct_ls_filter_cb,
_file_direct_ls_main_cb,
_file_done_cb,
_file_error_cb,
operation_data);
operation_data->file = handle;
promise->progress_notify = NULL;
}
static void
_free_notify_start_data(void *data)
{
Job_Closure *operation_data = (Job_Closure*)data;
if (!operation_data->delayed_arg)
return;
free(operation_data->delayed_arg);
operation_data->delayed_arg = NULL;
}
static void
_ls_notify_start(void *data, Eina_Promise_Owner* promise)
{
Job_Closure *operation_data = (Job_Closure*)data;
char* path = operation_data->delayed_arg;
Eio_File *handle = eio_file_ls(path,
_file_ls_filter_named_cb,
_file_ls_main_cb,
_file_done_cb,
_file_error_cb,
operation_data);
operation_data->file = handle;
promise->progress_notify = NULL; // Don't ever think about calling me again...
}
static void
_xattr_notify_start(void *data, Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = (Job_Closure*)data;
char* path = operation_data->delayed_arg;
Eio_File *handle = eio_file_xattr(path,
_file_ls_filter_xattr_cb,
_file_ls_main_cb,
_file_done_cb,
_file_error_cb,
operation_data);
operation_data->file = handle;
promise->progress_notify = NULL; // Don't ever think about calling me again...
}
static void
_job_direct_ls_helper(Eio_Job_Direct_Ls_Func ls_func,
Eo* obj,
Eio_Job_Data *pd,
const char *path,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
operation_data->delayed_arg = (char*)calloc(sizeof(char), strlen(path) + 1);
strcpy(operation_data->delayed_arg, path);
operation_data->direct_func = ls_func;
eina_promise_owner_progress_notify(promise,
_ls_direct_notify_start,
operation_data,
_free_notify_start_data);
}
/* Method implementations */
void
_eio_job_file_direct_ls(Eo *obj,
Eio_Job_Data *pd,
const char *path,
Eina_Promise_Owner *promise)
{
_job_direct_ls_helper(&eio_file_direct_ls, obj, pd, path, promise);
}
void
_eio_job_file_stat_ls(Eo *obj,
Eio_Job_Data *pd,
const char *path,
Eina_Promise_Owner *promise)
{
_job_direct_ls_helper(&eio_file_stat_ls, obj, pd, path, promise);
}
void
_eio_job_dir_stat_ls(Eo *obj,
Eio_Job_Data *pd,
const char *path,
Eina_Promise_Owner *promise)
{
_job_direct_ls_helper(&eio_dir_stat_ls, obj, pd, path, promise);
}
void
_eio_job_dir_direct_ls(Eo *obj EINA_UNUSED,
Eio_Job_Data *pd EINA_UNUSED,
const char *path,
Eina_Promise_Owner *promise EINA_UNUSED)
{
// Had to add the cast as dir_direct differs in the filter callback constness of one of
// its arguments.
_job_direct_ls_helper((Eio_Job_Direct_Ls_Func)&eio_dir_direct_ls, obj, pd, path, promise);
}
void
_eio_job_file_ls(Eo *obj,
Eio_Job_Data *pd,
const char *path,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
operation_data->delayed_arg = (char*)calloc(sizeof(char), strlen(path) + 1);
strcpy(operation_data->delayed_arg, path);
eina_promise_owner_progress_notify(promise,
_ls_notify_start,
operation_data,
_free_notify_start_data);
}
/* Stat function */
static void
_file_stat_done_cb(void *data, Eio_File *handle EINA_UNUSED, const Eina_Stat *stat)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN(operation);
EINA_SAFETY_ON_NULL_RETURN(operation->promise);
// Placeholder value. We just want the callback to be called.
eina_promise_owner_value_set(operation->promise, &stat, NULL);
_job_closure_del(operation);
}
void
_eio_job_file_direct_stat(Eo *obj,
Eio_Job_Data *pd,
const char *path,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
Eio_File *handle = eio_file_direct_stat(path,
_file_stat_done_cb,
_file_error_cb,
operation_data);
operation_data->file = handle;
}
/* eXtended attribute manipulation */
void
_eio_job_file_xattr(Eo *obj,
Eio_Job_Data *pd,
const char *path,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
operation_data->delayed_arg = (char*)calloc(sizeof(char), strlen(path) + 1);
strcpy(operation_data->delayed_arg, path);
eina_promise_owner_progress_notify(promise,
_xattr_notify_start,
operation_data,
_free_notify_start_data);
}
void
_eio_job_file_xattr_set(Eo *obj,
Eio_Job_Data *pd,
const char *path,
const char *attribute,
const char *xattr_data,
unsigned int xattr_size,
Eina_Xattr_Flags flags,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
Eio_File *handle = eio_file_xattr_set(path,
attribute,
xattr_data,
xattr_size,
flags,
_file_done_cb,
_file_error_cb,
operation_data);
operation_data->file = handle;
}
void
_eio_job_file_xattr_get(Eo *obj,
Eio_Job_Data *pd,
const char *path,
const char *attribute,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
Eio_File *handle = eio_file_xattr_get(path,
attribute,
_file_done_data_cb,
_file_error_cb,
operation_data);
operation_data->file = handle;
}
/* Eina_File mapping and handling. */
static void
_file_open_open_cb(void *data, Eio_File *handler EINA_UNUSED, Eina_File *file)
{
Job_Closure *operation = data;
EINA_SAFETY_ON_NULL_RETURN(operation);
EINA_SAFETY_ON_NULL_RETURN(operation->promise);
// FIXME On promise composition, a successfully open file would leak open
// another promise in the composition fails as there is no free/close
// function. Calling eina_file_close blocks on a lock_take call on a
// field of the Eina_File file.
eina_promise_owner_value_set(operation->promise, &file, NULL);
_job_closure_del(operation);
}
void
_eio_job_file_open(Eo *obj,
Eio_Job_Data *pd,
const char *path,
Eina_Bool shared,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
Eio_File *handle = eio_file_open(path, shared, _file_open_open_cb, _file_error_cb, operation_data);
operation_data->file = handle;
}
static
void _file_close_done_cb(void *data, Eio_File *handler EINA_UNUSED)
{
EINA_SAFETY_ON_NULL_RETURN(data);
Job_Closure *operation = data;
Eina_Bool result = EINA_TRUE;
eina_promise_owner_value_set(operation->promise, &result, NULL);
_job_closure_del(operation);
}
void _eio_job_file_close(Eo *obj,
Eio_Job_Data *pd,
Eina_File *file,
Eina_Promise_Owner *promise)
{
Job_Closure *operation_data = _job_closure_create(obj, pd, promise);
if (!operation_data)
{
EINA_LOG_CRIT("Failed to create eio job operation data.");
return;
}
Eio_File *handle = eio_file_close(file, _file_close_done_cb, _file_error_cb, operation_data);
operation_data->file = handle;
}
void _eio_job_cancel_all(Eo *obj EINA_UNUSED, Eio_Job_Data *pd EINA_UNUSED)
{
printf("%s called.\n", __FUNCTION__);
}
Eo_Base * _eio_job_eo_base_constructor(Eo *obj, Eio_Job_Data *pd EINA_UNUSED)
{
obj = eo_constructor(eo_super(obj, EIO_JOB_CLASS));
pd->object = obj;
pd->operations = NULL;
return obj;
}
void _eio_job_eo_base_destructor(Eo *obj, Eio_Job_Data *pd EINA_UNUSED)
{
eo_destructor(eo_super(obj, EIO_JOB_CLASS));
}
#include "eio_job.eo.c"

152
src/lib/eio/eio_job.eo Normal file
View File

@ -0,0 +1,152 @@
import eina_types;
struct Eio.Data
{
[[A structure to handle arbitrary data to be sent over Promises.]]
data: void *;
size: uint;
}
struct Eio.Filter.Direct.Data
{
info: const(Eina.File.Direct.Info)*;
filter: bool;
}
struct Eio.Filter.Name.Data
{
file: const(char)*;
filter: bool;
}
struct Eio.Xattr.Data
{
data: const(char)*;
size: uint;
}
class Eio.Job (Eo.Base)
{
[[Class representing an asynchronous file operation.]]
legacy_prefix: null;
methods {
// Listing operations
file_ls {
[[Lists entries in a given path.]]
params {
@in path: const(char)*;
@inout promise: promise<int, const(char)*>;
}
}
file_direct_ls {
[[Lists entries in a given path with more information.]]
params {
@in path: const(char)*;
@inout promise: promise<int, const(Eina_File_Direct_Info)*>;
}
}
file_stat_ls {
[[Lists entries in a given path with stat information.]]
params {
@in path: const(char)*;
@inout promise: promise<int, const(Eina_File_Direct_Info)*>;
}
}
dir_stat_ls {
[[Recursively list the directory content and its sub content.]]
params {
@in path: const(char)*;
@inout promise: promise<int, const(Eina_File_Direct_Info)*>;
}
}
dir_direct_ls {
[[Recursively list the directory content and its sub content.]]
params {
@in path: const(char)*;
@inout promise: promise<int, const(Eina_File_Direct_Info)*>;
}
}
file_direct_stat {
[[Get stat info on a given file/directory.]]
params {
@in path: const(char)*;
@inout promise: promise<const(Eina_Stat)*>; //TODO Change to a delayed promise.
}
}
// Extended attributes
file_xattr {
[[Lists all extended attributes asynchronously.]]
params {
@in path: const(char)*;
@inout promise: promise<int, const(char)*>;
}
}
file_xattr_set {
[[Sets a given extended attribute.]]
params {
@in path: const(char)*;
@in attribute: const(char)*;
@in xattr_data: const(char)*;
@in xattr_size: uint;
@in flags: Eina.Xattr.Flags;
@inout promise: promise<int>;
}
}
file_xattr_get {
[[Sets a given extended attribute.]]
params {
@in path: const(char)*;
@in attribute: const(char)*;
@inout promise: promise<Eio.Xattr.Data*>;
}
}
// helper api
file_open {
[[Opens a file.
The fulfilled value in the promise will be the Eina.File*.]]
params {
@in path: const(char)*;
@in shared: bool;
@inout promise: promise<Eina.File*>;
}
}
file_close {
[[Closes an open Eina.File.]]
params {
@in file: Eina.File*;
// Here we're just interested whether the promise was fullfilled or not. No value needed.
@inout promise: promise<int>;
}
}
cancel_all {
[[Cancels all pending operations on this job.]]
params {
// Shall we need some promise here?
}
}
}
events {
filter,name: Eio.Filter.Name.Data;
filter,direct: Eio.Filter.Direct.Data;
xattr: Eio.Filter.Name.Data;
}
implements {
Eo.Base.constructor;
Eo.Base.destructor;
}
}

View File

@ -0,0 +1,12 @@
#ifndef _EIO_FILE_PRIVATE_H
#define _EIO_FILE_PRIVATE_H
typedef struct _Eio_Job_Data Eio_Job_Data;
struct _Eio_Job_Data
{
Eo *object;
Eina_List *operations;
};
#endif

View File

@ -44,7 +44,7 @@ static void
_eio_file_open_free(Eio_File_Map *map)
{
if (map->name) eina_stringshare_del(map->name);
free(map);
eio_file_free((Eio_File*)map);
}
static void
@ -144,7 +144,7 @@ _eio_file_map_end(void *data, Ecore_Thread *thread EINA_UNUSED)
Eio_File_Map_Rule *map = data;
map->map_cb((void*) map->common.data, &map->common, map->result, map->length);
free(map);
eio_file_free((Eio_File*)map);
}
static void
@ -153,7 +153,7 @@ _eio_file_map_cancel(void *data, Ecore_Thread *thread EINA_UNUSED)
Eio_File_Map_Rule *map = data;
eio_file_error(&map->common);
free(map);
eio_file_free((Eio_File*)map);
}
/**

166
src/lib/eio/eio_sentry.c Normal file
View File

@ -0,0 +1,166 @@
/* EIO - EFL data type library
* Copyright (C) 2016 Enlightenment Developers:
* Lauro Moura <lauromoura@expertisesolutions.com.br>
*
* 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
#include <Eo.h>
#include "Ecore.h"
#include "Eio.h"
#include "eio_sentry_private.h"
static const Eo_Event_Description*
_translate_event(int input_event)
{
if (input_event == EIO_MONITOR_FILE_CREATED)
return EIO_SENTRY_EVENT_FILE_CREATED;
else if (input_event == EIO_MONITOR_FILE_DELETED)
return EIO_SENTRY_EVENT_FILE_DELETED;
else if (input_event == EIO_MONITOR_FILE_MODIFIED)
return EIO_SENTRY_EVENT_FILE_MODIFIED;
else if (input_event == EIO_MONITOR_FILE_CLOSED)
return EIO_SENTRY_EVENT_FILE_CLOSED;
else if (input_event == EIO_MONITOR_DIRECTORY_CREATED)
return EIO_SENTRY_EVENT_DIRECTORY_CREATED;
else if (input_event == EIO_MONITOR_DIRECTORY_DELETED)
return EIO_SENTRY_EVENT_DIRECTORY_DELETED;
else if (input_event == EIO_MONITOR_DIRECTORY_MODIFIED)
return EIO_SENTRY_EVENT_DIRECTORY_MODIFIED;
else if (input_event == EIO_MONITOR_DIRECTORY_CLOSED)
return EIO_SENTRY_EVENT_DIRECTORY_CLOSED;
else if (input_event == EIO_MONITOR_SELF_RENAME)
return EIO_SENTRY_EVENT_SELF_RENAME;
else if (input_event == EIO_MONITOR_SELF_DELETED)
return EIO_SENTRY_EVENT_SELF_DELETED;
else if (input_event == EIO_MONITOR_ERROR)
return EIO_SENTRY_EVENT_ERROR;
else
return NULL;
}
static unsigned char
_handle_event(void *data, int type, void *event)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(data, ECORE_CALLBACK_PASS_ON);
EINA_SAFETY_ON_NULL_RETURN_VAL(event, ECORE_CALLBACK_PASS_ON);
const Eo_Event_Description* translated_event = _translate_event(type);
Eio_Sentry_Data *pd = (Eio_Sentry_Data *)data;
Eio_Monitor_Event *monitor_event = (Eio_Monitor_Event *)event;
Eio_Sentry_Event *event_info = malloc(sizeof(Eio_Sentry_Event));
EINA_SAFETY_ON_NULL_RETURN_VAL(event_info, ECORE_CALLBACK_PASS_ON);
event_info->source = eio_monitor_path_get(monitor_event->monitor);
event_info->trigger = monitor_event->filename;
eo_event_callback_call(pd->object, translated_event, event_info);
// If event was error, we must delete the monitor.
if (type == EIO_MONITOR_ERROR)
eina_hash_del(pd->targets, event_info->source, NULL);
free(event_info);
return ECORE_CALLBACK_PASS_ON;
}
static void
_initialize_handlers(Eio_Sentry_Data *pd)
{
EINA_SAFETY_ON_NULL_RETURN(pd);
ecore_event_handler_add(EIO_MONITOR_FILE_CREATED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_FILE_DELETED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_FILE_CLOSED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_DIRECTORY_CREATED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_DIRECTORY_DELETED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_DIRECTORY_MODIFIED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_DIRECTORY_CLOSED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_SELF_RENAME, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_SELF_DELETED, _handle_event, pd);
ecore_event_handler_add(EIO_MONITOR_ERROR, _handle_event, pd);
pd->handlers_initialized = EINA_TRUE;
}
Eina_Bool
_eio_sentry_add(Eo *obj EINA_UNUSED, Eio_Sentry_Data *pd, const char *path)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(path, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(pd, EINA_FALSE);
if (!pd->handlers_initialized)
_initialize_handlers(pd);
if (eina_hash_find(pd->targets, path))
return EINA_TRUE;
Eio_Monitor *monitor = eio_monitor_add(path);
if (!monitor)
{
EINA_LOG_ERR("Failed to create monitor.");
return EINA_FALSE;
}
if (!eina_hash_add(pd->targets, path, monitor))
{
EINA_LOG_ERR("Failed to register monitor.");
eio_monitor_del(monitor);
return EINA_FALSE;
}
return EINA_TRUE;
}
void
_eio_sentry_del(Eo *obj EINA_UNUSED, Eio_Sentry_Data *pd, const char *path)
{
EINA_SAFETY_ON_NULL_RETURN(path);
EINA_SAFETY_ON_NULL_RETURN(pd);
eina_hash_del(pd->targets, path, NULL);
}
Eo_Base * _eio_sentry_eo_base_constructor(Eo *obj, Eio_Sentry_Data *pd)
{
obj = eo_constructor(eo_super(obj, EIO_SENTRY_CLASS));
pd->object = obj;
pd->targets = eina_hash_string_small_new((Eina_Free_Cb)&eio_monitor_del);
pd->handlers_initialized = EINA_FALSE;
return obj;
}
void _eio_sentry_eo_base_destructor(Eo *obj, Eio_Sentry_Data *pd)
{
eina_hash_free(pd->targets);
eo_destructor(eo_super(obj, EIO_SENTRY_CLASS));
}
#include "eio_sentry.eo.c"

49
src/lib/eio/eio_sentry.eo Normal file
View File

@ -0,0 +1,49 @@
import eina_types;
struct Eio.Sentry.Event
{
[[Wraps the data about a monitor event on a file.]]
trigger: const(char)*; [[The cause of the event.]]
source: const(char)*; [[The original monitored path.]]
}
class Eio.Sentry (Eo.Base)
{
[[Monitors files and directories for changes.]]
legacy_prefix: null;
methods {
add {
[[Adds a new path to the list of monitored paths.]]
params {
@in path: const(char)*;
}
return : bool;
}
del {
[[Removes the given path from the monitored list.]]
params {
@in path: const(char)*;
}
}
}
events {
file,created: Eio.Sentry.Event;
file,deleted: Eio.Sentry.Event;
file,modified: Eio.Sentry.Event;
file,closed: Eio.Sentry.Event;
directory,created: Eio.Sentry.Event;
directory,deleted: Eio.Sentry.Event;
directory,modified: Eio.Sentry.Event;
directory,closed: Eio.Sentry.Event;
self,rename: Eio.Sentry.Event;
self,deleted: Eio.Sentry.Event;
error: Eio.Sentry.Event;
}
implements {
Eo.Base.constructor;
Eo.Base.destructor;
}
}

View File

@ -0,0 +1,13 @@
#ifndef _EIO_SENTRY_PRIVATE_H
#define _EIO_SENTRY_PRIVATE_H
typedef struct _Eio_Sentry_Data Eio_Sentry_Data;
struct _Eio_Sentry_Data
{
Eo *object;
Eina_Hash *targets;
Eina_Bool handlers_initialized;
};
#endif

View File

@ -27,3 +27,11 @@ struct @extern Eina.Inarray;
type @extern Eina.Unicode: uint32;
struct @extern Eina.Value;
struct @extern Eina.File.Direct.Info;
enum Eina.Xattr.Flags {
insert, [[This is the default behaviour, it will either create or replace the extended attribute]]
replace, [[This will only succeed if the extended attribute previously existed]]
created [[This will only succeed if the extended attribute wasn't previously set]]
}

View File

@ -7,11 +7,14 @@
static const Efl_Test_Case etc[] = {
{"Eio_Monitor", eio_test_monitor},
{"Eio_Sentry", eio_test_sentry},
{"Eio Model", eio_model_test_file},
{"Eio Model Monitor", eio_model_test_monitor_add},
{"Eio File", eio_test_file},
{"Eio Job", eio_test_job},
#ifdef XATTR_TEST_DIR
{"Eio_Xattr", eio_test_xattr},
{"Eio Job Xattr", eio_test_job_xattr},
#endif
{NULL, NULL}
};

View File

@ -4,9 +4,12 @@
#include <check.h>
void eio_test_monitor(TCase *tc);
void eio_test_sentry(TCase *tc);
void eio_model_test_file(TCase *tc);
void eio_model_test_monitor_add(TCase *tc);
void eio_test_file(TCase *tc);
void eio_test_job(TCase *tc);
void eio_test_job_xattr(TCase *tc);
void eio_test_xattr(TCase *tc);
#endif /* _EIO_SUITE_H */

View File

@ -0,0 +1,89 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "eio_suite.h"
#include "eio_test_common.h"
#ifndef O_BINARY
# define O_BINARY 0
#endif
static const char *good_dirs[] =
{
"eio_file_ls_simple_dir",
"b."
};
unsigned int default_rights = DEFAULT_RIGHTS;
const char *files[] =
{
".hidden_file",
"~$b@:-*$a!{}",
"$b$a",
"normal_file"
};
Eina_Tmpstr*
get_full_path(const char* tmpdirname, const char* filename)
{
char full_path[PATH_MAX] = "";
eina_str_join(full_path, sizeof(full_path), '/', tmpdirname, filename);
return eina_tmpstr_add(full_path);
}
Eina_Tmpstr*
get_eio_test_file_tmp_dir()
{
Eina_Tmpstr *tmp_dir;
Eina_Bool created = eina_file_mkdtemp("EioFileTestXXXXXX", &tmp_dir);
if (!created)
{
return NULL;
}
return tmp_dir;
}
Eina_Tmpstr*
create_test_dirs(Eina_Tmpstr *test_dirname)
{
int i, fd;
int count = sizeof(good_dirs) / sizeof(const char *);
fail_if(test_dirname == NULL);
for (i = 0; i != count; ++i)
{
Eina_Tmpstr *dirname = get_full_path(test_dirname, good_dirs[i]);
fail_if(mkdir(dirname, default_rights) != 0);
eina_tmpstr_del(dirname);
}
count = sizeof(files) / sizeof(const char *);
for (i = 0; i != count; ++i)
{
Eina_Tmpstr *filename = get_full_path(test_dirname, files[i]);
fd = open(filename, O_RDWR | O_BINARY | O_CREAT, default_rights);
fail_if(fd < 0);
fail_if(close(fd) != 0);
eina_tmpstr_del(filename);
}
Eina_Tmpstr *nested_dirname = get_full_path(test_dirname, good_dirs[0]);
for (i = 0; i != count; ++i)
{
Eina_Tmpstr *filename = get_full_path(nested_dirname, files[i]);
fd = open(filename, O_RDWR | O_BINARY | O_CREAT, default_rights);
fail_if(fd < 0);
fail_if(close(fd) != 0);
eina_tmpstr_del(filename);
}
return nested_dirname;
}

View File

@ -0,0 +1,16 @@
#ifndef _EIO_TEST_COMMON_H
#define _EIO_TEST_COMMON_H
#include <Eina.h>
#define DEFAULT_RIGHTS 0755;
extern unsigned int default_rights;
extern const char *files[];
Eina_Tmpstr* get_full_path(const char* tmpdirname, const char* filename);
Eina_Tmpstr* get_eio_test_file_tmp_dir();
Eina_Tmpstr* create_test_dirs(Eina_Tmpstr *test_dirname);
#endif

View File

@ -13,25 +13,13 @@
#include <Eio.h>
#include "eio_suite.h"
#include "eio_test_common.h"
#ifndef O_BINARY
# define O_BINARY 0
#endif
static unsigned int default_rights = 0755;
static int test_count = 0;
static const char *good_dirs[] =
{
"eio_file_ls_simple_dir",
"b."
};
static const char *files[] =
{
".hidden_file",
"~$b@:-*$a!{}",
"$b$a",
"normal_file"
};
static Eina_Bool
_filter_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const char *file)
@ -118,61 +106,13 @@ _error_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, int error)
ecore_main_loop_quit();
}
Eina_Tmpstr*
get_full_path(const char* tmpdirname, const char* filename)
static void
_open_done_cb(void *data, Eio_File *handler EINA_UNUSED, Eina_File *file)
{
char full_path[PATH_MAX] = "";
eina_str_join(full_path, sizeof(full_path), '/', tmpdirname, filename);
return eina_tmpstr_add(full_path);
}
Eina_Tmpstr*
get_eio_test_file_tmp_dir()
{
Eina_Tmpstr *tmp_dir;
Eina_Bool created = eina_file_mkdtemp("EioFileTestXXXXXX", &tmp_dir);
if (!created)
{
return NULL;
}
return tmp_dir;
}
Eina_Tmpstr*
create_test_dirs(Eina_Tmpstr *test_dirname)
{
int i, fd;
int count = sizeof(good_dirs) / sizeof(const char *);
fail_if(test_dirname == NULL);
for (i = 0; i != count; ++i)
{
Eina_Tmpstr *dirname = get_full_path(test_dirname, good_dirs[i]);
fail_if(mkdir(dirname, default_rights) != 0);
eina_tmpstr_del(dirname);
}
count = sizeof(files) / sizeof(const char *);
for (i = 0; i != count; ++i)
{
Eina_Tmpstr *filename = get_full_path(test_dirname, files[i]);
fd = open(filename, O_RDWR | O_BINARY | O_CREAT, default_rights);
fail_if(fd < 0);
fail_if(close(fd) != 0);
eina_tmpstr_del(filename);
}
Eina_Tmpstr *nested_dirname = get_full_path(test_dirname, good_dirs[0]);
for (i = 0; i != count; ++i)
{
Eina_Tmpstr *filename = get_full_path(nested_dirname, files[i]);
fd = open(filename, O_RDWR | O_BINARY | O_CREAT, default_rights);
fail_if(fd < 0);
fail_if(close(fd) != 0);
eina_tmpstr_del(filename);
}
return nested_dirname;
Eina_Bool *opened = (Eina_Bool *)data;
*opened = EINA_TRUE;
eina_file_close(file);
ecore_main_loop_quit();
}
START_TEST(eio_file_test_ls)
@ -288,6 +228,7 @@ START_TEST(eio_file_test_file)
is_dir = EINA_FALSE;
eio_file_direct_stat(nested_filename, _stat_done_cb, _error_cb, &is_dir);
ecore_main_loop_begin();
default_rights = DEFAULT_RIGHTS;
test_count = 1;
eio_file_move(nested_filename, new_filename, _progress_cb, _done_cb,
@ -368,9 +309,47 @@ START_TEST(eio_file_test_file)
}
END_TEST
START_TEST(eio_file_test_open)
{
Eina_Bool opened_file;
int ret;
ret = ecore_init();
fail_if(ret < 1);
ret = eio_init();
fail_if(ret < 1);
ret = eina_init();
fail_if(ret < 1);
ret = ecore_file_init();
fail_if(ret < 1);
Eina_Tmpstr *test_dirname = get_eio_test_file_tmp_dir();
Eina_Tmpstr *nested_dirname = create_test_dirs(test_dirname);
Eina_Tmpstr *nested_filename = get_full_path(test_dirname, files[3]);
opened_file = EINA_FALSE;
eio_file_open(nested_filename, EINA_FALSE, _open_done_cb, _error_cb, &opened_file);
ecore_main_loop_begin();
fail_if(!opened_file);
// Cleanup
fail_if(!ecore_file_recursive_rm(test_dirname));
eina_tmpstr_del(nested_dirname);
eina_tmpstr_del(test_dirname);
eina_tmpstr_del(nested_filename);
ecore_file_shutdown();
eina_shutdown();
eio_shutdown();
ecore_shutdown();
}
END_TEST
void
eio_test_file(TCase *tc)
{
tcase_add_test(tc, eio_file_test_ls);
tcase_add_test(tc, eio_file_test_file);
tcase_add_test(tc, eio_file_test_open);
}

View File

@ -0,0 +1,287 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <Ecore.h>
#include <Ecore_File.h>
#include <Eio.h>
#include "eio_suite.h"
#include "eio_test_common.h"
#ifndef O_BINARY
# define O_BINARY 0
#endif
static int test_count = 0;
static int DONE_CALLED = 0xdeadbeef;
static void
_filter_direct_cb(void *data EINA_UNUSED, const Eo_Event *event)
{
Eio_Filter_Direct_Data *event_info = event->info;
char *last_slash = strrchr(event_info->info->path, '/');
//Check if it is a hidden file
if (last_slash != NULL && strlen(last_slash) > 1 && last_slash[1] == '.')
event_info->filter = EINA_FALSE;
else
event_info->filter = EINA_TRUE;
}
static void
_main_direct_cb(void *data, const Eina_File_Direct_Info *info)
{
int *number_of_listed_files = (int *)data;
fprintf(stderr, "Processing file:%s\n", info->path);
(*number_of_listed_files)++;
}
static void
_filter_cb(void *data EINA_UNUSED, const Eo_Event *event)
{
Eio_Filter_Name_Data *event_info = event->info;
char *last_slash = strrchr(event_info->file, '/');
//Check if it is a hidden file
if (last_slash != NULL && strlen(last_slash) > 1 && last_slash[1] == '.')
event_info->filter = EINA_FALSE;
else
event_info->filter = EINA_TRUE;
}
static void
_main_cb(void *data, const char *file)
{
int *number_of_listed_files = (int *)data;
fprintf(stderr, "Processing file:%s\n", file);
(*number_of_listed_files)++;
}
static void
_done_cb(void *data, Eio_File *handler EINA_UNUSED)
{
int *number_of_listed_files = (int *)data;
fail_if((*number_of_listed_files) != test_count);
*number_of_listed_files = DONE_CALLED;
ecore_main_loop_quit();
}
static void
_error_cb(void *data EINA_UNUSED, Eina_Error *error)
{
const char *msg = eina_error_msg_get(*error);
EINA_LOG_ERR("error: %s", msg);
ecore_main_loop_quit();
}
static void
_open_done_cb(void *data, Eina_File **file)
{
Eina_Bool *opened = (Eina_Bool *)data;
*opened = EINA_TRUE;
eina_file_close(*file);
ecore_main_loop_quit();
}
static void
_stat_done_cb(void *data, const Eina_Stat **stat)
{
Eina_Bool *is_dir = (Eina_Bool *)data;
unsigned int rights;
fail_if(eio_file_is_dir(*stat) != *is_dir);
fail_if(eio_file_is_lnk(*stat));
rights = (*stat)->mode & (S_IRWXU | S_IRWXG | S_IRWXO);
fail_if(rights != default_rights);
ecore_main_loop_quit();
}
typedef void (*Eio_Job_Test_Stat_Ls_Func)(Eo *job, const char *path, Eina_Promise **promise);
static void
_do_ls_test(Eio_Job_Test_Stat_Ls_Func ls_func,
const Eo_Event_Description *event,
Eo_Event_Cb filter_cb,
Eina_Promise_Progress_Cb progress_cb,
int expected_test_count,
const char* test_dirname)
{
int main_files = 0;
Eio_Job *job = eo_add(EIO_JOB_CLASS, NULL);
Eina_Promise *promise = NULL;
eo_event_callback_add(job, event, filter_cb, NULL);
ls_func(job, test_dirname, &promise);
test_count = expected_test_count;
eina_promise_progress_cb_add(promise, progress_cb, &main_files, NULL);
eina_promise_then(promise,
(Eina_Promise_Cb)&_done_cb,
(Eina_Promise_Error_Cb)&_error_cb,
&main_files);
ecore_main_loop_begin();
fail_if(main_files != DONE_CALLED);
eo_unref(job);
}
static void
_do_direct_ls_test(Eio_Job_Test_Stat_Ls_Func ls_func,
int expected_test_count,
const char *test_dirname)
{
_do_ls_test(ls_func,
EIO_JOB_EVENT_FILTER_DIRECT,
(Eo_Event_Cb)&_filter_direct_cb,
(Eina_Promise_Progress_Cb)&_main_direct_cb,
expected_test_count,
test_dirname);
}
START_TEST(eio_job_test_file_direct_stat)
{
Eina_Bool is_dir;
int ret;
ret = ecore_init();
fail_if(ret < 1);
ret = eio_init();
fail_if(ret < 1);
ret = eina_init();
fail_if(ret < 1);
ret = ecore_file_init();
fail_if(ret < 1);
Eina_Tmpstr *test_dirname = get_eio_test_file_tmp_dir();
Eina_Tmpstr *nested_dirname = create_test_dirs(test_dirname);
Eina_Tmpstr *nested_filename = get_full_path(test_dirname, files[3]);
Eio_Job *job = eo_add(EIO_JOB_CLASS, NULL);
Eina_Promise *promise = NULL;
// Start testing
is_dir = EINA_TRUE;
eio_job_file_direct_stat(job, nested_dirname, &promise);
eina_promise_then(promise, (Eina_Promise_Cb)&_stat_done_cb, (Eina_Promise_Error_Cb)&_error_cb, &is_dir);
ecore_main_loop_begin();
is_dir = EINA_FALSE;
eio_job_file_direct_stat(job, nested_filename, &promise);
eina_promise_then(promise, (Eina_Promise_Cb)&_stat_done_cb, (Eina_Promise_Error_Cb)&_error_cb, &is_dir);
ecore_main_loop_begin();
eo_unref(job);
// Cleanup
fail_if(!ecore_file_recursive_rm(test_dirname));
eina_tmpstr_del(nested_dirname);
eina_tmpstr_del(test_dirname);
eina_tmpstr_del(nested_filename);
ecore_file_shutdown();
eina_shutdown();
eio_shutdown();
ecore_shutdown();
}
END_TEST
START_TEST(eio_job_test_ls_funcs)
{
int ret;
ret = ecore_init();
fail_if(ret < 1);
ret = eio_init();
fail_if(ret < 1);
ret = eina_init();
fail_if(ret < 1);
ret = ecore_file_init();
fail_if(ret < 1);
Eina_Tmpstr *test_dirname = get_eio_test_file_tmp_dir();
Eina_Tmpstr *nested_dirname = create_test_dirs(test_dirname);
Eina_Tmpstr *nested_filename = get_full_path(test_dirname, files[3]);
// Start testing
_do_ls_test(&eio_job_file_ls,
EIO_JOB_EVENT_FILTER_NAME,
(Eo_Event_Cb)&_filter_cb,
(Eina_Promise_Progress_Cb)&_main_cb,
5,
test_dirname);
_do_direct_ls_test(&eio_job_file_stat_ls, 5, test_dirname);
_do_direct_ls_test(&eio_job_file_direct_ls, 5, test_dirname);
_do_direct_ls_test(&eio_job_dir_stat_ls, 8, test_dirname);
_do_direct_ls_test(&eio_job_dir_direct_ls, 8, test_dirname);
// Cleanup
fail_if(!ecore_file_recursive_rm(test_dirname));
eina_tmpstr_del(nested_dirname);
eina_tmpstr_del(test_dirname);
eina_tmpstr_del(nested_filename);
ecore_file_shutdown();
eina_shutdown();
eio_shutdown();
ecore_shutdown();
}
END_TEST
START_TEST(eio_job_test_open)
{
Eina_Bool opened_file;
int ret;
ret = ecore_init();
fail_if(ret < 1);
ret = eio_init();
fail_if(ret < 1);
ret = eina_init();
fail_if(ret < 1);
ret = ecore_file_init();
fail_if(ret < 1);
Eina_Tmpstr *test_dirname = get_eio_test_file_tmp_dir();
Eina_Tmpstr *nested_dirname = create_test_dirs(test_dirname);
Eina_Tmpstr *nested_filename = get_full_path(test_dirname, files[3]);
opened_file = EINA_FALSE;
Eio_Job *job = eo_add(EIO_JOB_CLASS, NULL);
Eina_Promise *promise = NULL;
eio_job_file_open(job, nested_filename, EINA_FALSE, &promise);
eina_promise_then(promise, (Eina_Promise_Cb)&_open_done_cb, (Eina_Promise_Error_Cb)&_error_cb, &opened_file);
ecore_main_loop_begin();
eo_unref(job);
fail_if(!opened_file);
// Cleanup
fail_if(!ecore_file_recursive_rm(test_dirname));
eina_tmpstr_del(nested_dirname);
eina_tmpstr_del(test_dirname);
eina_tmpstr_del(nested_filename);
ecore_file_shutdown();
eina_shutdown();
eio_shutdown();
ecore_shutdown();
}
END_TEST
void
eio_test_job(TCase *tc)
{
tcase_add_test(tc, eio_job_test_ls_funcs);
tcase_add_test(tc, eio_job_test_file_direct_stat);
tcase_add_test(tc, eio_job_test_open);
}
;

View File

@ -0,0 +1,204 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <Ecore.h>
#include <Ecore_File.h>
#include <Eio.h>
#include "eio_suite.h"
#include "eio_test_common.h"
#ifdef XATTR_TEST_DIR
static const char *attribute[] =
{
"user.comment1",
"user.comment2",
"user.comment3"
};
static const char *attr_data[] =
{
"This is a test file",
"This line is a comment",
"This file has extra attributes"
};
struct eina_iterator
{
Eina_Iterator* success_iterator;
Eina_Iterator* failure_iterator;
};
int total_attributes = sizeof(attribute)/sizeof(attribute[0]);
static Eina_Bool
_filter_cb(void *data EINA_UNUSED, const Eo_Event *event)
{
Eio_Filter_Name_Data *event_info = event->info;
return event_info->filter = EINA_TRUE;
}
static void
_main_cb(void *data, const char *attr)
{
int *num_of_attr = (int *)data;
unsigned int i;
for (i = 0; i < sizeof (attribute) / sizeof (attribute[0]); ++i)
if (strcmp(attr, attribute[i]) == 0)
{
(*num_of_attr)++;
break;
}
}
static void
_done_cb(void *data, void *value EINA_UNUSED)
{
int *num_of_attr = (int *)data;
fail_if(*num_of_attr != total_attributes);
ecore_main_loop_quit();
}
static void
_done_get_cb(void *data EINA_UNUSED, struct eina_iterator* it)
{
int i = 0;
Eio_Xattr_Data *get_data;
while (eina_iterator_next(it->success_iterator, (void**)&get_data))
{
fail_if(!get_data);
fail_if(strcmp(get_data->data, attr_data[i]) != 0);
i++;
}
fail_if(i != total_attributes);
ecore_main_loop_quit();
}
static void
_done_set_cb(void *data, struct eina_iterator* it)
{
int *placeholder;
int *num_of_attr = data;
while(eina_iterator_next(it->success_iterator, (void**)&placeholder))
*num_of_attr += 1;
fail_if(*num_of_attr != total_attributes);
ecore_main_loop_quit();
}
static void
_error_cb(void *data EINA_UNUSED, Eina_Error *error)
{
fprintf(stderr, "Something has gone wrong:%s\n", strerror(*error));
abort();
ecore_main_loop_quit();
}
START_TEST(eio_test_job_xattr_set)
{
char *filename = "eio-tmpfile";
Eina_Tmpstr *test_file_path;
int num_of_attr = 0, fd;
unsigned int i;
Eo *job;
Eina_Promise *list_promise = NULL;
Eina_Promise **attrib_promises = NULL;
ecore_init();
eina_init();
eio_init();
job = eo_add(EIO_JOB_CLASS, NULL);
test_file_path = get_full_path(XATTR_TEST_DIR, filename);
fd = open(test_file_path,
O_WRONLY | O_CREAT | O_TRUNC,
S_IRWXU | S_IRWXG | S_IRWXO);
fail_if(fd == 0);
attrib_promises = (Eina_Promise **)calloc(total_attributes + 1, sizeof(Eina_Promise*));
attrib_promises[total_attributes] = NULL;
for (i = 0; i < sizeof(attribute) / sizeof(attribute[0]); ++i)
{
eio_job_file_xattr_set(job, test_file_path, attribute[i],
attr_data[i], strlen(attr_data[i]),
EINA_XATTR_INSERT,
&attrib_promises[i]);
fail_if(num_of_attr != 0); // test asynchronous
}
eina_promise_then(eina_promise_all(eina_carray_iterator_new((void**)attrib_promises)),
(Eina_Promise_Cb)_done_set_cb, (Eina_Promise_Error_Cb)_error_cb, &num_of_attr);
ecore_main_loop_begin();
free(attrib_promises);
num_of_attr = 0;
attrib_promises = (Eina_Promise **)calloc(total_attributes + 1, sizeof(Eina_Promise*));
attrib_promises[total_attributes] = NULL;
for (i = 0; i < sizeof(attribute) / sizeof(attribute[0]); ++i)
{
eio_job_file_xattr_get(job, test_file_path, attribute[i], &attrib_promises[i]);
}
eina_promise_then(eina_promise_all(eina_carray_iterator_new((void**)attrib_promises)),
(Eina_Promise_Cb)_done_get_cb, (Eina_Promise_Error_Cb)_error_cb, &num_of_attr);
ecore_main_loop_begin();
num_of_attr = 0;
eo_event_callback_add(job, EIO_JOB_EVENT_XATTR, _filter_cb, NULL);
eio_job_file_xattr(job, test_file_path, &list_promise);
eina_promise_progress_cb_add(list_promise, (Eina_Promise_Progress_Cb)_main_cb, &num_of_attr, NULL);
eina_promise_then(list_promise, (Eina_Promise_Cb)_done_cb, (Eina_Promise_Error_Cb)_error_cb, &num_of_attr);
fail_if(num_of_attr != 0);
ecore_main_loop_begin();
free(attrib_promises);
eo_unref(job);
close(fd);
unlink(test_file_path);
eina_tmpstr_del(test_file_path);
eio_shutdown();
eina_shutdown();
ecore_shutdown();
}
END_TEST
#endif
void eio_test_job_xattr(TCase *tc)
{
#ifdef XATTR_TEST_DIR
tcase_add_test(tc, eio_test_job_xattr_set);
#else
(void)tc;
#endif
}

View File

@ -0,0 +1,755 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <Ecore.h>
#include <Ecore_File.h>
#include <Eio.h>
#include "eio_suite.h"
/////////////////timeout function
#define TEST_TIMEOUT_SEC 10
#define TEST_OPERATION_DELAY 0.5
static Ecore_Timer *test_timeout_timer;
static Eina_Bool _test_timeout_cb(void *data EINA_UNUSED)
{
ck_abort_msg("test timeout");
ecore_main_loop_quit();
return ECORE_CALLBACK_CANCEL;
}
static void _cancel_timeout()
{
if (test_timeout_timer != NULL)
{
ecore_timer_del (test_timeout_timer);
test_timeout_timer = NULL;
}
}
static Eina_Bool _test_timeout_expected(void *data EINA_UNUSED)
{
if (test_timeout_timer != NULL)
{
_cancel_timeout();
}
ecore_main_loop_quit();
return ECORE_CALLBACK_CANCEL;
}
///////////////// file and directory operations
typedef struct {
const char *src;
const char *dst;
} RenameOperation;
static Eina_Bool _delete_directory(void *data)
{
const char *dirname = (const char*)data;
if (ecore_file_is_dir(dirname))
{
ecore_file_recursive_rm(dirname);
}
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _create_directory(void *data)
{
const char *dirname = (const char*)data;
ecore_file_mkpath(dirname);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _create_file(void *data)
{
FILE *fd = fopen((const char*)data, "wb+");
ck_assert_ptr_ne(fd, NULL);
fprintf(fd, "test test");
fclose(fd);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _delete_file(void *data)
{
Eina_Bool file_removed = ecore_file_remove((const char*)data);
ck_assert(file_removed);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _modify_file(void *data)
{
FILE *fd = fopen((const char*)data, "ab");
ck_assert_ptr_ne(fd, NULL);
fprintf(fd, "appened");
fclose(fd);
return ECORE_CALLBACK_CANCEL;
}
static Eina_Bool _modify_attrib_file(void *data)
{
int ret = chmod((const char*)data, 0666);
ck_assert_int_eq(ret, 0);
return ECORE_CALLBACK_CANCEL;
}
/////// helper functions
static Eina_Bool _check_event_path(void *data, const Eo_Event *event)
{
Eio_Sentry_Event *event_info = event->info;
ck_assert_str_eq((const char*)data, event_info->trigger);
return EINA_TRUE;
}
static Eina_Tmpstr *_common_init()
{
Eina_Tmpstr *dirname;
fail_if(eio_init() != 1);
ecore_file_init();
//test timeout
test_timeout_timer = ecore_timer_add(TEST_TIMEOUT_SEC, _test_timeout_cb, NULL);
eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname);
return dirname;
}
static void _common_shutdown(Eina_Tmpstr *dirname)
{
_delete_directory((void*)dirname);
ecore_file_shutdown();
fail_if(eio_shutdown() != 0);
eina_tmpstr_del(dirname);
}
/////// tests monitoring a directory
START_TEST(eio_test_sentry_add_and_remove)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_file_created_notify", dirname);
_create_directory((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
fail_if(!eio_sentry_add(sentry, filename));
usleep(500000);
eio_sentry_del(sentry, filename);
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_add_remove_add)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo* sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_add_remove_add", dirname);
_create_directory((void*)filename);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
fail_if(!eio_sentry_add(sentry, filename));
eio_sentry_del(sentry, filename);
usleep(500000);
fail_if(!eio_sentry_add(sentry, filename));
eio_sentry_del(sentry, filename);
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_add_add_remove_remove)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename1;
Eina_Stringshare *filename2;
Eo *sentry;
filename1 = eina_stringshare_printf("%s/eio_test_sentry_add_add_remove_remove", dirname);
filename2 = eina_stringshare_printf("%s/eio_test_sentry_add_add_remove_remove", dirname);
_create_directory((void*)filename1);
_create_directory((void*)filename2);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//monitor directory
fail_if(!eio_sentry_add(sentry, filename1));
fail_if(!eio_sentry_add(sentry, filename2));
usleep(500000);
eio_sentry_del(sentry, filename1);
eio_sentry_del(sentry, filename2);
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
static void _target_notified_cb(void *data, const Eo_Event *event)
{
if (_check_event_path(data, event))
{
_cancel_timeout();
ecore_main_loop_quit();
}
}
START_TEST(eio_test_sentry_directory_file_created_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo* sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_file_created_notify", dirname);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_CREATED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_directory_file_deleted_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_file_deleted_notify", dirname);
_create_file((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_DELETED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _delete_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_directory_file_modified_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_file_modified_notify", dirname);
_create_file((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_MODIFIED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
//cleanup
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_directory_file_closed_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_file_closed_notify", dirname);
_create_file((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_CLOSED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_directory_directory_created_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_directory_created_notify", dirname);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_DIRECTORY_CREATED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_directory, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_directory_directory_deleted_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_directory_deleted_notify", dirname);
_create_directory((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_DIRECTORY_DELETED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _delete_directory, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_directory_directory_modified_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_directory_directory_modified_notify", dirname);
_create_directory((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_DIRECTORY_MODIFIED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_attrib_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_directory_directory_self_deleted_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eo *sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_SELF_DELETED, (Eo_Event_Cb)_target_notified_cb, dirname);
ecore_timer_add(TEST_OPERATION_DELAY, _delete_directory, dirname);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
// //////// test monitoring a single file
START_TEST(eio_test_sentry_file_file_modified_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/filecreated", dirname);
_create_file((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
fail_if(!eio_sentry_add(sentry, filename));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_MODIFIED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
//cleanup
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_file_file_attrib_modified_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_file_file_attrib_modified_notify", dirname);
_create_file((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
fail_if(!eio_sentry_add(sentry, filename));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_MODIFIED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_attrib_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_file_file_closed_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo* sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_file_file_closed_notify", dirname);
_create_file((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
fail_if(!eio_sentry_add(sentry, dirname));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_CLOSED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_file_file_self_deleted_notify)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eo* sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_file_file_self_deleted_notify", dirname);
_create_file((void*)filename);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
fail_if(!eio_sentry_add(sentry, filename));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_SELF_DELETED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _delete_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_two_monitors_one_event)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Tmpstr *dirname2;
Eo *sentry;
Eina_Stringshare *filename;
eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
filename = eina_stringshare_printf("%s/eio_test_sentry_two_monitors_one_event", dirname);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
fail_if(!eio_sentry_add(sentry, dirname2));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_CREATED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_delete_directory((void*)dirname2);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_two_monitors_one_removed_one_event)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Tmpstr *dirname2;
Eo *sentry;
Eina_Stringshare *filename;
eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
filename = eina_stringshare_printf("%s/eio_test_sentry_two_monitors_one_removed", dirname);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname2));
fail_if(!eio_sentry_add(sentry, dirname));
eio_sentry_del(sentry, dirname2);
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_CREATED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
_delete_directory((void*)dirname2);
_common_shutdown(dirname);
}
END_TEST
static void _unexpected_event_cb(void *data EINA_UNUSED, const Eo_Event *event EINA_UNUSED)
{
ck_abort_msg("unexpected event");
}
START_TEST(eio_test_sentry_two_monitors_one_removed_no_event)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Tmpstr *dirname2;
Eo *sentry;
Eina_Stringshare *filename;
eina_file_mkdtemp("checkFileCreationXXXXXX", &dirname2);
filename = eina_stringshare_printf("%s/eio_test_sentry_two_monitors_one_removed", dirname);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor directory
fail_if(!eio_sentry_add(sentry, dirname));
fail_if(!eio_sentry_add(sentry, dirname2));
eio_sentry_del(sentry, dirname);
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_CREATED, (Eo_Event_Cb)_unexpected_event_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _create_file, filename);
ecore_timer_add(TEST_TIMEOUT_SEC - 1, _test_timeout_expected, NULL);
ecore_main_loop_begin();
eo_unref(sentry);
_delete_directory((void*)dirname2);
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_two_files_in_same_directory)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eina_Stringshare *filename2;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_two_files_in_same_directory_1", dirname);
filename2 = eina_stringshare_printf("%s/eio_test_sentry_two_files_in_same_directory_2", dirname);
_create_file((void*)filename);
_create_file((void*)filename2);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
fail_if(!eio_sentry_add(sentry,filename));
fail_if(!eio_sentry_add(sentry,filename2));
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_MODIFIED, (Eo_Event_Cb)_target_notified_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_main_loop_begin();
eo_unref(sentry);
//cleanup
_common_shutdown(dirname);
}
END_TEST
START_TEST(eio_test_sentry_two_files_in_same_directory_one_removed)
{
Eina_Tmpstr *dirname = _common_init();
Eina_Stringshare *filename;
Eina_Stringshare *filename2;
Eo *sentry;
filename = eina_stringshare_printf("%s/eio_test_sentry_two_files_in_same_directory_one_removed_1", dirname);
filename2 = eina_stringshare_printf("%s/eio_test_sentry_two_files_in_same_directory_one_removed_2", dirname);
_create_file((void*)filename);
_create_file((void*)filename2);
sentry = eo_add(EIO_SENTRY_CLASS, NULL);
//sleep to avoid catching event generated by above manipulations
usleep(500000);
//monitor file
fail_if(!eio_sentry_add(sentry,filename));
fail_if(!eio_sentry_add(sentry,filename2));
eio_sentry_del(sentry, filename);
eo_event_callback_add(sentry, EIO_SENTRY_EVENT_FILE_MODIFIED, (Eo_Event_Cb)_unexpected_event_cb, filename);
ecore_timer_add(TEST_OPERATION_DELAY, _modify_file, filename);
ecore_timer_add(TEST_TIMEOUT_SEC - 1, _test_timeout_expected, NULL);
ecore_main_loop_begin();
eo_unref(sentry);
//cleanup
_common_shutdown(dirname);
}
END_TEST
void eio_test_sentry(TCase *tc)
{
tcase_add_test(tc, eio_test_sentry_add_and_remove);
tcase_add_test(tc, eio_test_sentry_add_remove_add);
tcase_add_test(tc, eio_test_sentry_add_add_remove_remove);
tcase_add_test(tc, eio_test_sentry_directory_file_created_notify);
tcase_add_test(tc, eio_test_sentry_directory_file_deleted_notify);
tcase_add_test(tc, eio_test_sentry_directory_file_modified_notify);
#if !defined(_WIN32) && !defined(__MACH__)
tcase_add_test(tc, eio_test_sentry_directory_file_closed_notify);
#endif
tcase_add_test(tc, eio_test_sentry_directory_directory_created_notify);
tcase_add_test(tc, eio_test_sentry_directory_directory_deleted_notify);
tcase_add_test(tc, eio_test_sentry_directory_directory_modified_notify);
#ifndef __MACH__
tcase_add_test(tc, eio_test_sentry_directory_directory_self_deleted_notify);
#endif
tcase_add_test(tc, eio_test_sentry_file_file_modified_notify);
tcase_add_test(tc, eio_test_sentry_file_file_attrib_modified_notify);
#if !defined(_WIN32) && !defined(__MACH__)
tcase_add_test(tc, eio_test_sentry_file_file_closed_notify);
#endif
#ifndef __MACH__
tcase_add_test(tc, eio_test_sentry_file_file_self_deleted_notify);
#endif
tcase_add_test(tc, eio_test_sentry_two_monitors_one_event);
tcase_add_test(tc, eio_test_sentry_two_monitors_one_removed_one_event);
tcase_add_test(tc, eio_test_sentry_two_monitors_one_removed_no_event);
tcase_add_test(tc, eio_test_sentry_two_files_in_same_directory);
tcase_add_test(tc, eio_test_sentry_two_files_in_same_directory_one_removed);
}

View File

@ -12,6 +12,7 @@
#include <Eio.h>
#include "eio_suite.h"
#include "eio_test_common.h"
#ifdef XATTR_TEST_DIR
@ -23,27 +24,19 @@ static int int_data = 1234;
static char *double_attr = "user.size";
static double double_data = 123.456;
const char *attribute[] =
static const char *attribute[] =
{
"user.comment1",
"user.comment2",
"user.comment3"
};
const char *attr_data[] =
static const char *attr_data[] =
{
"This is a test file",
"This line is a comment",
"This file has extra attributes"
};
Eina_Tmpstr*
get_file_path(const char* tmpdirname, const char* filename)
{
char file_path[PATH_MAX] = "";
eina_str_join(file_path, sizeof(file_path), '/', tmpdirname, filename);
return eina_tmpstr_add(file_path);
}
static Eina_Bool
_filter_cb(void *data EINA_UNUSED, Eio_File *handler EINA_UNUSED, const char *attr EINA_UNUSED)
{
@ -149,7 +142,7 @@ START_TEST(eio_test_xattr_set)
eina_init();
eio_init();
test_file_path = get_file_path(XATTR_TEST_DIR, filename);
test_file_path = get_full_path(XATTR_TEST_DIR, filename);
fd = open(test_file_path,
O_WRONLY | O_CREAT | O_TRUNC,
S_IRWXU | S_IRWXG | S_IRWXO);
@ -207,7 +200,7 @@ START_TEST(eio_test_xattr_types_set)
eina_init();
eio_init();
test_file_path = get_file_path(XATTR_TEST_DIR, filename);
test_file_path = get_full_path(XATTR_TEST_DIR, filename);
fd = open(test_file_path,
O_WRONLY | O_CREAT | O_TRUNC,
S_IRWXU | S_IRWXG | S_IRWXO);