From 13665444098d5aec5beaf7f1eacb93b2707db3a0 Mon Sep 17 00:00:00 2001 From: Jinkun Jang Date: Wed, 13 Mar 2013 01:52:57 +0900 Subject: [PATCH] Tizen 2.1 base --- AUTHORS | 7 + COPYING | 18 + ChangeLog | 57 ++ Makefile.am | 48 +- NEWS | 37 + README | 27 + TODO | 1 + autogen.sh | 25 +- configure.ac | 261 ++++++- doc/Doxyfile.in | 1630 +++++++++++++++++++++++++++++++++++++++++ doc/Makefile.am | 32 + doc/e.css | 218 ++++++ doc/eio.dox.in | 456 ++++++++++++ doc/foot.html | 19 + doc/head.html | 67 ++ doc/img/e.png | Bin 0 -> 3825 bytes doc/img/edoxy.css | 483 ++++++++++++ doc/img/foot_bg.png | Bin 0 -> 173 bytes doc/img/head_bg.png | Bin 0 -> 214 bytes doc/img/menu_bg.png | Bin 0 -> 192 bytes doc/img/menu_bg_current.png | Bin 0 -> 1200 bytes doc/img/menu_bg_hover.png | Bin 0 -> 3278 bytes doc/img/menu_bg_last.png | Bin 0 -> 637 bytes doc/img/menu_bg_unsel.png | Bin 0 -> 1596 bytes eio.manifest | 5 + eio.spec.in | 60 ++ m4/efl_examples.m4 | 63 ++ m4/efl_threads.m4 | 206 ++++++ m4/eio_check_options.m4 | 86 +++ packaging/eio.spec | 61 ++ src/Makefile.am | 3 +- src/examples/Makefile.am | 30 + src/examples/eio_file_ls.c | 74 ++ src/lib/Eio.h | 1151 ++++++++++++++++++++++++++++- src/lib/Makefile.am | 28 +- src/lib/eio_dir.c | 1001 +++++++++++++++++++++++++ src/lib/eio_eet.c | 640 ++++++++++++++++ src/lib/eio_file.c | 1008 +++++++++++++++++++++---- src/lib/eio_inline_helper.x | 105 +++ src/lib/eio_main.c | 300 ++++++++ src/lib/eio_map.c | 316 ++++++++ src/lib/eio_monitor.c | 351 +++++++++ src/lib/eio_monitor_inotify.c | 273 +++++++ src/lib/eio_monitor_poll.c | 354 +++++++++ src/lib/eio_monitor_win32.c | 425 +++++++++++ src/lib/eio_private.h | 512 +++++++++++++ src/lib/eio_single.c | 594 +++++++++++++++ src/lib/eio_xattr.c | 500 +++++++++++++ 48 files changed, 11297 insertions(+), 235 deletions(-) create mode 100644 TODO create mode 100644 doc/Doxyfile.in create mode 100644 doc/Makefile.am create mode 100644 doc/e.css create mode 100644 doc/eio.dox.in create mode 100644 doc/foot.html create mode 100644 doc/head.html create mode 100644 doc/img/e.png create mode 100644 doc/img/edoxy.css create mode 100644 doc/img/foot_bg.png create mode 100644 doc/img/head_bg.png create mode 100644 doc/img/menu_bg.png create mode 100644 doc/img/menu_bg_current.png create mode 100644 doc/img/menu_bg_hover.png create mode 100644 doc/img/menu_bg_last.png create mode 100644 doc/img/menu_bg_unsel.png create mode 100644 eio.manifest create mode 100644 eio.spec.in create mode 100644 m4/efl_examples.m4 create mode 100644 m4/efl_threads.m4 create mode 100644 m4/eio_check_options.m4 create mode 100644 packaging/eio.spec create mode 100644 src/examples/Makefile.am create mode 100644 src/examples/eio_file_ls.c create mode 100644 src/lib/eio_dir.c create mode 100644 src/lib/eio_eet.c create mode 100644 src/lib/eio_inline_helper.x create mode 100644 src/lib/eio_main.c create mode 100644 src/lib/eio_map.c create mode 100644 src/lib/eio_monitor.c create mode 100644 src/lib/eio_monitor_inotify.c create mode 100644 src/lib/eio_monitor_poll.c create mode 100644 src/lib/eio_monitor_win32.c create mode 100644 src/lib/eio_private.h create mode 100644 src/lib/eio_single.c create mode 100644 src/lib/eio_xattr.c diff --git a/AUTHORS b/AUTHORS index 8266484..27aeadc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,8 @@ Cedric Bail +Stephen Houston +Gustavo Sverzut Barbieri +Vincent "caro" Torri +Mikael SANS +Mike Blumenkrantz (zmike/discomfitor) +Jérôme Pinot +Daniel Willmann diff --git a/COPYING b/COPYING index cf546d2..63f364e 100644 --- a/COPYING +++ b/COPYING @@ -1,3 +1,21 @@ +Copyright notice for EIO: + +Copyright (C) 2010-2011 Cedric Bail and various contributors (see AUTHORS) + +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; version 2.1 of the License. + +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. + +Below is a copy of the GNU Lesser General Public License that is distributed +along with this library. If you do not have a copy below, write to the Free +Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA + GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 diff --git a/ChangeLog b/ChangeLog index e69de29..bc42978 100644 --- a/ChangeLog +++ b/ChangeLog @@ -0,0 +1,57 @@ +2012-04-26 Carsten Haitzler (The Rasterman) + + * 1.0.0 release + +2012-04-30 Jérôme Pinot + + * Fix build out of tree. + +2012-05-09 Cedric Bail + + * Actually test if we are really requesting to monitor the same file. + +2012-08-02 Cedric Bail + + * Fix a memory leak when shutting down fallback monitor. + +2012-08-07 Cedric Bail + + * Properly shutdown monitor when calling eio_shutdown. + +2012-08-21 Cedric Bail + + * Add a comment describing the false positiv detected by static analyzer + when calling eio_file_set. + +2012-08-07 Vincent Torri + + * Do not free Windows stuff when it is not used. Fix seg fault + * Add log debugging macros + +2012-08-30 Cedric Bail + + * Fix memory leak when using file associate API. + +2012-08-30 Carsten Haitzler (The Rasterman) + + 1.7.0 release + +2012-09-06 Vincent Torri + + * Improve file monitoring on Windows to mimic more inotify behavior. + +2012-09-10 Cedric Bail + + * Fix monitor shutdown when mainloop did never run. + +2012-09-14 Cedric Bail + + * Fix build with xattr without splice. + +2012-09-27 Cedric Bail + + * Don't stop on limited access right. + +2012-10-03 Daniel Willmann + * Fix memory corruption by allocating enough memory in + eio_eet_data_read_cipher(). diff --git a/Makefile.am b/Makefile.am index eaf2bb9..2fad093 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,12 +1,13 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = src +SUBDIRS = src doc MAINTAINERCLEANFILES = \ ABOUT-NLS \ Makefile.in \ aclocal.m4 \ -autom4te.cache \ +compile \ +config.cache-env \ config.guess \ config.h.in \ config.h.in~ \ @@ -25,31 +26,28 @@ m4/libtool.m4 \ m4/lt~obsolete.m4 \ m4/ltoptions.m4 \ m4/ltsugar.m4 \ -m4/ltversion.m4 \ -m4/codeset.m4 \ -m4/gettext.m4 \ -m4/glibc21.m4 \ -m4/iconv.m4 \ -m4/intdiv0.m4 \ -m4/inttypes_h.m4 \ -m4/inttypes.m4 \ -m4/inttypes-pri.m4 \ -m4/isc-posix.m4 \ -m4/lcmessage.m4 \ -m4/lib-ld.m4 \ -m4/lib-link.m4 \ -m4/lib-prefix.m4 \ -m4/nls.m4 \ -m4/po.m4 \ -m4/progtest.m4 \ -m4/stdint_h.m4 \ -m4/uintmax_t.m4 \ -m4/ulonglong.m4 +m4/ltversion.m4 -EXTRA_DIST = AUTHORS COPYING COPYING-PLAIN \ - autogen.sh \ - eio.pc.in +EXTRA_DIST = \ +AUTHORS \ +COPYING \ +README \ +autogen.sh \ +eio.spec \ +eio.pc.in \ +m4/ac_attribute.m4 \ +m4/efl_doxygen.m4 \ +m4/efl_path_max.m4 \ +m4/efl_threads.m4 \ +m4/eio_check_options.m4 pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = eio.pc +.PHONY: doc coverage benchmark + +# Documentation + +doc: + @echo "entering doc/" + make -C doc doc diff --git a/NEWS b/NEWS index e69de29..1fddc65 100644 --- a/NEWS +++ b/NEWS @@ -0,0 +1,37 @@ +Eio 1.8.0 + +Changes since Eio 1.7.0: +------------------------- + +Additions: + +Fixes: + - fix monitor shutdown when mainloop did never run. + - fix build with xattr and without splice. + - don't stop on limited access right. + - Fix memory corruption by allocating enough memory in eio_eet_data_read_cipher(). + +Improvements: + +Removal: + +Eio 1.7.0 + +Changes since Eio 1.0.0: +------------------------- + +Additions: + +Fixes: + - build out of tree. + - detect when requesting to monitor a different file with the same name. + - memory leak when shutting down fallback monitor. + - properly shutdown monitor. + - Fix segfault when shutting down the Windows monitor. + - Fix memory leak when using file_associate. + +Improvements: + - Add log debugging macros. + - path monitoring on Windows. + +Removal: diff --git a/README b/README index e69de29..a59326a 100644 --- a/README +++ b/README @@ -0,0 +1,27 @@ +EIO 1.7.99 + +****************************************************************************** + + FOR ANY ISSUES PLEASE EMAIL: + enlightenment-devel@lists.sourceforge.net + +****************************************************************************** + +Enlightenment Input Output Library +================================== + +This library is intended to provide non blocking IO by using thread for all +operations that may block. It depends only on eina, eet and ecore right now. +It should integrate all the features/functions of Ecore_File that could block. + +It is part of what we call the EFL and can be a dependence of E17. Feel free +to contribute, help is always appreciated ! + +------------------------------------------------------------------------------ +COMPILING AND INSTALLING: + + ./configure + make +(do this as root unless you are installing in your users directories): + make install + diff --git a/TODO b/TODO new file mode 100644 index 0000000..01c6f05 --- /dev/null +++ b/TODO @@ -0,0 +1 @@ + * Fix file monitoring on Windows when we pass a file and not just a directory \ No newline at end of file diff --git a/autogen.sh b/autogen.sh index 995ff2f..00116ea 100755 --- a/autogen.sh +++ b/autogen.sh @@ -4,6 +4,7 @@ rm -rf autom4te.cache rm -f aclocal.m4 ltmain.sh touch README +touch ABOUT-NLS echo "Running aclocal..." ; aclocal $ACLOCAL_FLAGS -I m4 || exit 1 echo "Running autoheader..." ; autoheader || exit 1 @@ -11,6 +12,28 @@ echo "Running autoconf..." ; autoconf || exit 1 echo "Running libtoolize..." ; (libtoolize --copy --automake || glibtoolize --automake) || exit 1 echo "Running automake..." ; automake --add-missing --copy --gnu || exit 1 +W=0 + +rm -f config.cache-env.tmp +echo "OLD_PARM=\"$@\"" >> config.cache-env.tmp +echo "OLD_CFLAGS=\"$CFLAGS\"" >> config.cache-env.tmp +echo "OLD_PATH=\"$PATH\"" >> config.cache-env.tmp +echo "OLD_PKG_CONFIG_PATH=\"$PKG_CONFIG_PATH\"" >> config.cache-env.tmp +echo "OLD_LDFLAGS=\"$LDFLAGS\"" >> config.cache-env.tmp + +cmp config.cache-env.tmp config.cache-env >> /dev/null +if [ $? -ne 0 ]; then + W=1; +fi + +if [ $W -ne 0 ]; then + echo "Cleaning configure cache..."; + rm -f config.cache config.cache-env + mv config.cache-env.tmp config.cache-env +else + rm -f config.cache-env.tmp +fi + if [ -z "$NOCONFIGURE" ]; then - ./configure "$@" + ./configure -C "$@" fi diff --git a/configure.ac b/configure.ac index a45911c..4f14a6a 100644 --- a/configure.ac +++ b/configure.ac @@ -1,15 +1,15 @@ ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## -m4_define([v_maj], [0]) -m4_define([v_min], [9]) -m4_define([v_mic], [9]) -m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v export || echo 0) | awk -F : '{printf("%s\n", $1);}' | tr -d ' :MSP\n'])) +m4_define([v_maj], [1]) +m4_define([v_min], [7]) +m4_define([v_mic], [99]) +m4_define([v_rev], m4_esyscmd([(svnversion "${SVN_REPO_PATH:-.}" | grep -v '\(export\|Unversioned directory\)' || echo 0) | awk -F : '{printf("%s\n", $1);}' | tr -d ' :MSP\n'])) m4_if(v_rev, [0], [m4_define([v_rev], m4_esyscmd([git log 2> /dev/null | (grep -m1 git-svn-id || echo 0) | sed -e 's/.*@\([0-9]*\).*/\1/' | tr -d '\n']))]) ##-- When released, remove the dnl on the below line dnl m4_undefine([v_rev]) ##-- When doing snapshots - change soname. remove dnl on below line -m4_define([relname], [ver-pre-svn-07]) -m4_define([v_rel], [-release relname]) +dnl m4_define([relname], [ver-pre-svn-09]) +dnl m4_define([v_rel], [-release relname]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_ifdef([v_rev], [m4_define([v_ver], [v_maj.v_min.v_mic.v_rev])], [m4_define([v_ver], [v_maj.v_min.v_mic])]) @@ -19,22 +19,28 @@ m4_define([lt_age], v_min) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## -AC_INIT([eio], [0.0.1], [enlightenment-devel@lists.sourceforge.net]) -release="ver-pre-svn-07" +AC_INIT([eio], [v_ver], [enlightenment-devel@lists.sourceforge.net]) AC_PREREQ([2.52]) AC_CONFIG_SRCDIR([configure.ac]) AC_CONFIG_MACRO_DIR([m4]) -AC_CANONICAL_BUILD -AC_CANONICAL_HOST -AC_ISC_POSIX + +AC_CONFIG_HEADERS([config.h]) +AH_TOP([ +#ifndef EFL_CONFIG_H__ +#define EFL_CONFIG_H__ +]) +AH_BOTTOM([ +#endif /* EFL_CONFIG_H__ */ +]) AM_INIT_AUTOMAKE([1.6 dist-bzip2]) -AM_CONFIG_HEADER([config.h]) m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) AC_GNU_SOURCE +AC_SYS_LARGEFILE AC_LIBTOOL_WIN32_DLL +define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl AC_PROG_LIBTOOL @@ -42,41 +48,124 @@ AC_PROG_LIBTOOL ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## m4_ifdef([v_rev], , [m4_define([v_rev], [0])]) m4_ifdef([v_rel], , [m4_define([v_rel], [])]) -AC_DEFINE_UNQUOTED(VERS_MAJ, [v_maj], [Major version]) -AC_DEFINE_UNQUOTED(VERS_MIN, [v_min], [Minor version]) -AC_DEFINE_UNQUOTED(VERS_MIC, [v_mic], [Micro version]) -AC_DEFINE_UNQUOTED(VERS_REV, [v_rev], [Revison]) +AC_DEFINE_UNQUOTED(VMAJ, [v_maj], [Major version]) +AC_DEFINE_UNQUOTED(VMIN, [v_min], [Minor version]) +AC_DEFINE_UNQUOTED(VMIC, [v_mic], [Micro version]) +AC_DEFINE_UNQUOTED(VREV, [v_rev], [Revison]) version_info="lt_rev:lt_cur:lt_age" release_info="v_rel" -AC_SUBST(version_info) -AC_SUBST(release_info) +AC_SUBST([version_info]) +AC_SUBST([release_info]) ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## ##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--##--## VMAJ=v_maj -AC_SUBST(VMAJ) +AC_SUBST([VMAJ]) -AC_LIBTOOL_WIN32_DLL -define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl -define([AC_LIBTOOL_LANG_F77_CONFIG], [:])dnl -AC_PROG_LIBTOOL -dnl we just have set the version info, then: -AC_SUBST(version_info) +### Needed information + +AC_CANONICAL_BUILD +AC_CANONICAL_HOST + + +### Default options with respect to host + +want_inotify="no" +want_notify_win32="no" + +case "$host_os" in + mingw*) + want_notify_win32="yes" + ;; + *) + want_inotify="yes" + ;; +esac + + +### Checks for programs AC_PROG_CC -PKG_CHECK_MODULES([EIO], [eina-0 ecore]) +# pkg-config +PKG_PROG_PKG_CONFIG + +# Check whether pkg-config supports Requires.private +if $PKG_CONFIG --atleast-pkgconfig-version 0.22; then + pkgconfig_requires_private="Requires.private" +else + pkgconfig_requires_private="Requires" +fi +AC_SUBST([pkgconfig_requires_private]) + +# doxygen program for documentation building + +EFL_CHECK_DOXYGEN([build_doc="yes"], [build_doc="no"]) + + +### Checks for libraries + +EFL_EIO_BUILD="" +case "$host_os" in + mingw*) + PKG_CHECK_EXISTS([evil >= 1.6.99]) + AC_DEFINE([HAVE_EVIL], [1], [Set to 1 if evil package is installed]) + requirements_eio="${requirements_eio} evil >= 1.6.99" + EFL_EIO_BUILD="-DEFL_EIO_BUILD" + ;; +esac +AC_SUBST([EFL_EIO_BUILD]) + +requirements_eio="${requirements_eio} eet >= 1.6.99 eina >= 1.6.99 ecore >= 1.6.99" +AC_SUBST([requirements_eio]) + +PKG_CHECK_MODULES([EIO], [${requirements_eio}]) + ### Checks for header files -AC_HEADER_ASSERT + AC_HEADER_DIRENT AC_HEADER_TIME +AC_CHECK_HEADERS([unistd.h libgen.h grp.h features.h pwd.h]) -### Checks for types +EFL_CHECK_THREADS( + [ + if test "x${_efl_have_posix_threads}" = "xyes" ; then + have_threads="POSIX" + else + if test "x${_efl_have_win32_threads}" = "xyes" ; then + have_threads="Win32" + else + have_threads="no" + fi + fi + ], + [have_threads="no"]) + +if test "x${have_threads}" = "xno" ; then + AC_MSG_ERROR([Threads not supported. Be sure to have pthread on non Windows OS]) +fi +EFL_CHECK_PATH_MAX + +### Checks for types ### Checks for structures +### Checks for compiler characteristics +AC_C_BIGENDIAN +AC_C_INLINE +AC_C___ATTRIBUTE__ +AM_PROG_CC_C_O + +EFL_EIO_BUILD="" +case "$host_os" in + mingw*) + EFL_EIO_BUILD="-DEFL_EIO_BUILD" + ;; +esac +AC_SUBST(EFL_EIO_BUILD) + ### Checks for linker characteristics # use --enable-auto-import on Windows @@ -89,23 +178,99 @@ case "$host_os" in esac AC_SUBST(lt_enable_auto_import) -### Checks for compiler characteristics -AC_C_CONST -AC_C_BIGENDIAN -AC_C_INLINE -AC_C___ATTRIBUTE__ -AC_PROG_CC_STDC -AM_PROG_CC_C_O - ### Checks for library functions -AC_FUNC_ALLOCA -AC_CHECK_FUNCS(strlcpy) +AC_CHECK_FUNCS([fchmod chown getpwnam getgrnam]) + +### Check for splice system call + +AC_MSG_CHECKING([whether to use splice for file copy]) +AC_TRY_LINK( + [ +#if defined(HAVE_UNISTD_H) +# include +#endif +#include + ], + [ +long ret = splice(0,0,1,0,400,0); + ], + [have_splice="yes"], + [have_splice="no"]) +AC_MSG_RESULT([${have_splice}]) + +if test "x${have_splice}" = "xyes" ; then + AC_DEFINE([HAVE_SPLICE], [1], [Define to mention that splice syscall is supported]) +fi + +# Check for lstat + +AC_MSG_CHECKING([whether lstat is available]) +AC_TRY_LINK( + [ +#include +#include +#if defined(HAVE_UNISTD_H) +# include +#endif + ], + [ +struct stat st; +lstat("/tmp", &st); + ], + [have_lstat="yes"], + [have_lstat="no"]) +AC_MSG_RESULT([${have_lstat}]) + +if test "x${have_lstat}" = "xyes" ; then + AC_DEFINE([HAVE_LSTAT], [1], [Define to mention that lstat syscall is supported]) +fi + +# extended attribute + +AC_MSG_CHECKING([for extended attributes]) + +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ +#include +#include +#include + ]], + [[ +size_t tmp = listxattr("/", NULL, 0); +tmp = getxattr("/", "user.ethumb.md5", NULL, 0); +setxattr("/", "user.ethumb.md5", NULL, 0, 0); + ]])], + [ + AC_DEFINE([HAVE_XATTR], [1], [Define to 1 if you have the `listxattr', `setxattr' and `getxattr' functions.]) + have_xattr="yes" + ], + [have_xattr="no"]) + +AC_MSG_RESULT([${have_xattr}]) + +# Check for inotify specificity +have_inotify="no" +have_notify_win32="no" +EIO_CHECK_INOTIFY([${want_inotify}], [have_inotify="yes"], [have_inotify="no"]) +EIO_CHECK_NOTIFY_WIN32([${want_notify_win32}], [have_notify_win32="yes"], [have_notify_win32="no"]) + +AM_CONDITIONAL([EIO_HAVE_INOTIFY], [test "x$have_inotify" = "xyes"]) +AM_CONDITIONAL([EIO_HAVE_WINCHANGE], [test "x$have_notify_win32" = "xyes"]) +EFL_CHECK_BUILD_EXAMPLES([enable_build_examples="yes"], [enable_build_examples="no"]) +EFL_CHECK_INSTALL_EXAMPLES([enable_install_examples="yes"], [enable_install_examples="no"]) + AC_OUTPUT([ eio.pc +eio.spec Makefile +doc/Makefile +doc/eio.dox +doc/Doxyfile src/Makefile src/lib/Makefile +src/examples/Makefile ]) echo @@ -114,3 +279,23 @@ echo "------------------------------------------------------------------------" echo "$PACKAGE_NAME $PACKAGE_VERSION" echo "------------------------------------------------------------------------" echo +echo +echo +echo "Configuration Options Summary:" +echo +echo " Thread Support.......: ${have_threads}" +echo " Inotify..............: ${have_inotify}" +echo " Windows notification.: ${have_notify_win32}" +echo +echo " Documentation........: ${build_doc}" +echo " Examples...............: ${enable_build_examples}" +echo " Examples installed.....: ${enable_install_examples}" +echo +echo "Compilation............: make (or gmake)" +echo " CPPFLAGS.............: $CPPFLAGS" +echo " CFLAGS...............: $CFLAGS" +echo " LDFLAGS..............: $LDFLAGS" +echo +echo "Installation...........: make install (as root if needed, with 'su' or 'sudo')" +echo " prefix...............: $prefix" +echo diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in new file mode 100644 index 0000000..dbcc001 --- /dev/null +++ b/doc/Doxyfile.in @@ -0,0 +1,1630 @@ +# Doxyfile 1.7.1 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project +# +# All text after a hash (#) is considered a comment and will be ignored +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" ") + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or a sequence of words surrounded +# by quotes) that should identify the project. + +PROJECT_NAME = Eio + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = @PACKAGE_VERSION@ + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = . + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = NO + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful is your file systems +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = NO + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also make the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen to replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penality. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will rougly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols + +SYMBOL_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = YES + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespace are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = NO + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = NO + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = NO + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = NO + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or define consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and defines in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = NO + +# If the sources in your project are distributed over multiple directories +# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy +# in the documentation. The default is NO. + +SHOW_DIRECTORIES = NO + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = NO + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command , where is the value of +# the FILE_VERSION_FILTER tag, and is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# This WARN_NO_PARAMDOC option can be abled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = @top_srcdir@/src/lib eio.dox + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx +# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90 + +FILE_PATTERNS = *.c *.h + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = YES + +# The EXCLUDE tag can be used to specify files and/or directories that should +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. + +EXCLUDE = ../src/lib/eio_private.h + +# The EXCLUDE_SYMLINKS tag can be used select whether or not files or +# directories that are symbolic links (a Unix filesystem feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = img + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command , where +# is the value of the INPUT_FILTER tag, and is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER +# is applied to all files. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = YES + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. + +HTML_HEADER = @srcdir@/head.html + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = @srcdir@/foot.html + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# stylesheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = @srcdir@/e.css + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the stylesheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = YES + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = org.doxygen.Project + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# +# Qt Help Project / Custom Filters. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# +# Qt Help Project / Filter Attributes. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index at +# top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. + +DISABLE_INDEX = YES + +# This tag can be used to set the number of enum values (range [1..20]) +# that doxygen will group on one line in the generated HTML documentation. + +ENUM_VALUES_PER_LINE = 4 + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. + +GENERATE_TREEVIEW = NO + +# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories, +# and Class Hierarchy pages using a tree view instead of an ordered list. + +USE_INLINE_TREES = NO + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvances is that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, a4wide, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = NO + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = NO + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# in the INCLUDE_PATH (see below) will be search if a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all function-like macros that are alone +# on a line, have an all uppercase name, and do not end with a semicolon. Such +# function macros are typically used for boiler-plate code, and will confuse +# the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. +# Optionally an initial location of the external documentation +# can be added for each tagfile. The format of a tag file without +# this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths or +# URLs. If a location is present for each tag, the installdox tool +# does not have to be run to correct the links. +# Note that each tag file must have a unique name +# (where the name does NOT include the path) +# If a tag file is not located in the directory in which doxygen +# is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option is superseded by the HAVE_DOT option below. This is only a +# fallback. It is recommended to install and use dot, since it yields more +# powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will write a font called FreeSans.ttf to the output +# directory and reference it in all dot files that doxygen generates. This +# font does not include all possible unicode characters however, so when you need +# these (or just want a differently looking font) you can specify the font name +# using DOT_FONTNAME. You need need to make sure dot is able to find the font, +# which can be done by putting it in a standard location or by setting the +# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory +# containing the font. + +DOT_FONTNAME = FreeSans.ttf + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the output directory to look for the +# FreeSans.ttf font (which doxygen will put there itself). If you specify a +# different font using DOT_FONTNAME you can set the path where dot +# can find it using this tag. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# the CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are png, jpg, or gif +# If left blank png will be used. + +DOT_IMAGE_FORMAT = png + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = NO + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/doc/Makefile.am b/doc/Makefile.am new file mode 100644 index 0000000..fcf2a28 --- /dev/null +++ b/doc/Makefile.am @@ -0,0 +1,32 @@ +MAINTAINERCLEANFILES = Makefile.in + +.PHONY: doc + +PACKAGE_DOCNAME = $(PACKAGE_TARNAME)-$(PACKAGE_VERSION)-doc + +if EFL_BUILD_DOC + +doc-clean: + rm -rf html/ latex/ man/ xml/ $(PACKAGE_DOCNAME).tar* + +doc: all + $(efl_doxygen) + cp $(srcdir)/img/* html/ + rm -rf $(PACKAGE_DOCNAME).tar* + mkdir -p $(PACKAGE_DOCNAME)/doc + cp -R html/ latex/ man/ $(PACKAGE_DOCNAME)/doc + tar cf $(PACKAGE_DOCNAME).tar $(PACKAGE_DOCNAME)/ + bzip2 -9 $(PACKAGE_DOCNAME).tar + rm -rf $(PACKAGE_DOCNAME)/ + mv $(PACKAGE_DOCNAME).tar.bz2 $(top_builddir) + +clean-local: doc-clean + +else + +doc: + @echo "Documentation not built. Run ./configure --help" + +endif + +EXTRA_DIST = $(builddir)/Doxyfile $(wildcard $(srcdir)/img/*.*) $(srcdir)/e.css $(srcdir)/head.html $(srcdir)/foot.html diff --git a/doc/e.css b/doc/e.css new file mode 100644 index 0000000..8697a3a --- /dev/null +++ b/doc/e.css @@ -0,0 +1,218 @@ +/* + Author: + Andres Blanc + DaveMDS Andreoli + + Supported Browsers: + ie7, opera9, konqueror4 and firefox3 + + Please use a different file for ie6, ie5, etc. hacks. +*/ + + +/* Necessary to place the footer at the bottom of the page */ +html, body { + height: 100%; + margin: 0px; + padding: 0px; +} + +#container { + min-height: 100%; + height: auto !important; + height: 100%; + margin: 0 auto -53px; +} + +#footer, #push { + height: 53px; +} + + +* html #container { + height: 100%; +} + +/* Prevent floating elements overflowing containers */ +.clear { + clear: both; + width: 0px; + height: 0px; +} + +/* Flexible & centered layout from 750 to 960 pixels */ +.layout { + max-width: 960px; + min-width: 760px; + margin-left: auto; + margin-right: auto; +} + +body { + /*font-family: Lucida Grande, Helvetica, sans-serif;*/ + font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif +} + +/* Prevent design overflowing the viewport in small resolutions */ +#container { + padding-right: 17px; + padding-left: 17px; + background-image: url(head_bg.png); + background-repeat: repeat-x; +} + +#header { + width: 100%; + height: 102px; +} + +#header h1 { + width: 63px; + height: 63px; + background-image: url(e.png); + background-repeat: no-repeat; + position: absolute; + margin: 0px; +} + +#header h1 span { + display: none; +} + +#header h2 { + display: none; +} + +/* .menu-container is used to set properties common to .menu and .submenu */ +#header .menu-container { +} + +#header .menu-container ul { + list-style-type: none; + list-style-position: inside; + margin: 0; +} + +#header .menu-container li { + display: block; + float: right; +} + +#header .menu { + height: 63px; + display: block; + background-image: url(menu_bg.png); + background-repeat: repeat-x; +} + +#header .menu ul { + height: 100%; + display: block; + background-image: url(menu_bg_last.png); + background-repeat: no-repeat; + background-position: top right; + padding-right: 17px; +} + +#header .menu li { + height: 100%; + text-align: center; + background-image: url(menu_bg_unsel.png); + background-repeat: no-repeat; +} + +#header .menu a { + height: 100%; + display: block; + color: #cdcdcd; + text-decoration: none; + font-size: 10pt; + line-height: 59px; + text-align: center; + padding: 0px 15px 0px 15px; +} + +#header .menu li:hover { + background-image: url(menu_bg_hover.png); + background-repeat: no-repeat; +} + +#header .menu li:hover a { + color: #FFFFFF; +} + +#header .menu li.current { + background-image: url(menu_bg_current.png); + background-repeat: no-repeat; +} + +#header .menu li.current a { + color: #646464; +} + + +/* Hide all the submenus but the current */ +#header .submenu ul { + display: none; +} + +#header .submenu .current { + display: block; +} + +#header .submenu { + font: bold 10px verdana,'Bitstream Vera Sans',helvetica,arial,sans-serif; + margin-top: 10px; +} + +#header .submenu a { + color: #888888; + text-decoration: none; + font-size: 0.9em; + line-height: 15px; + padding:0px 5px 0px 5px; +} + +#header .submenu a:hover { + color: #444444; +} + +#header .submenu li { + border-left: 1px solid #DDDDDD; +} + +#header .submenu li:last-child { + border-left: 0; +} + +#header .doxytitle { + position: absolute; + font-size: 1.8em; + font-weight: bold; + color: #444444; + line-height: 35px; +} + +#header small { + font-size: 0.4em; +} + +#footer { + background-image: url(foot_bg.png); + width: 100%; +} + +#footer table { + width: 100%; + text-align: center; + white-space: nowrap; + padding: 5px 30px 5px 30px; + font-size: 0.8em; + font-family: "Bitstream Vera","Vera","Trebuchet MS",Trebuchet,Tahoma,sans-serif; + color: #888888; +} + +#footer td.copyright { + width: 100%; +} + diff --git a/doc/eio.dox.in b/doc/eio.dox.in new file mode 100644 index 0000000..32a97b7 --- /dev/null +++ b/doc/eio.dox.in @@ -0,0 +1,456 @@ +/* EIO - EFL data type library + * Copyright (C) 2010 Enlightenment Developers: + * Cedric Bail + * Vincent "caro" Torri + * Stephen "okra" Houston + * Gustavo Sverzut Barbieri + * + * 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 . + */ + +/** + * @mainpage Eio + * @author Cedric Bail + * @author Stephen "okra" Houston + * @author Gustavo Sverzut Barbieri + * @author Vincent "caro" Torri + * @author Guillaume "kuri" Friloux + * @date 2010-2012 + * + * @section eio_intro_sec Introduction + * @version @PACKAGE_VERSION@ + * + * The Eio library is a library that implements an API for asynchronous + * input/output operation. Most operation are done in a separated thread + * to prevent lock. See @ref Eio_Group. Some helper to work on data + * received in Eio callback are also provided see @ref Eio_Helper. + * It is also possible to work asynchronously on Eina_File with @ref Eio_Map + * or on Eet_File with @ref Eio_Eet. It come with way to manipulate + * eXtended attribute assynchronously with @ref Eio_Xattr. + * + * This library is cross-platform and can be compiled and used on + * Linux, BSD, Opensolaris and Windows (XP and CE). + */ + +/** + * @page tutorial_dir_copy eio_dir_copy() tutorial + * + * To use eio_dir_copy(), you basically need the source and + * destination files (or directories), and set three callbacks: + * + * @li The notification callback, which allows you to know if a file or + * a directory is copied, and the progress of the copy. + * @li The end callback, which is called when the copy is finished. + * @li The error callback, which is called if an error occured. You + * can then retrieve the error type as an errno error. + * + * @warning It is the user's duty to provide the "right target". It + * means that copying to '.' will copy the content directly inside '.' + * and not in a subdirectory. + * + * Here is a simple example: + * + * @code + * #include + * #include + * + * static void + * _test_notify_cb(void *data, Eio_File *handler, const Eio_Progress *info) + * { + * switch (info->op) + * { + * case EIO_FILE_COPY: + * printf("[%s] %f%%\n", info->dest, info->percent); + * break; + * case EIO_DIR_COPY: + * printf("global [%li/%li] %f%%\n", info->current, info->max, info->percent); + * break; + * } + * } + * + * static void + * _test_done_cb(void *data, Eio_File *handler) + * { + * printf("copy done\n"); + * ecore_main_loop_quit(); + * } + * + * static void + * _test_error_cb(int error, Eio_File *handler, void *data) + * { + * fprintf(stderr, "error: [%s]\n", strerror(error)); + * ecore_main_loop_quit(); + * } + * + * int + * main(int argc, char **argv) + * { + * Eio_File *cp; + * + * if (argc != 3) + * { + * fprintf(stderr, "eio_cp source_file destination_file\n"); + * return -1; + * } + * + * ecore_init(); + * eio_init(); + * + * cp = eio_dir_copy(argv[1], argv[2], + * _test_notify_cb, + * _test_done_cb, + * _test_error_cb, + * NULL); + * + * ecore_main_loop_begin(); + * + * eio_shutdown(); + * ecore_shutdown(); + * + * return 0; + * } + * @endcode + */ + +/** + * @page tutorial_dir_stat_ls eio_dir_stat_ls() tutorial + * + * @li The filter callback, which allow or not a file to be seen + * by the main loop handler. This callback run in a separated thread. + * @li The main callback, which receive in the main loop all the file + * that are allowed by the filter. If you are updating a user interface + * it make sense to delay the insertion a little, so you get a chance + * to update the canvas for a bunch of file instead of one by one. + * @li The end callback, which is called in the main loop when the + * content of the directory has been correctly scanned and all the + * file notified to the main loop. + * @li The error callback, which is called if an error occured or + * if the listing was cancelled during it's run. You can then retrieve + * the error type as an errno error. + * + * Here is a simple example that implement a stupidly simple replacement for find: + * + * @code + * #include + * #include + * + * static Eina_Bool + * _test_filter_cb(void *data, Eio_File *handler, const Eina_File_Direct_Info *info) + * { + * fprintf(stderr, "ACCEPTING: %s\n", info->path); + * return EINA_TRUE; + * } + * + * static void + * _test_main_cb(void *data, Eio_File *handler, const Eina_File_Direct_Info *info) + * { + * fprintf(stderr, "PROCESS: %s\n", info->path); + * } + * + * static void + * _test_done_cb(void *data, Eio_File *handler) + * { + * printf("ls done\n"); + * ecore_main_loop_quit(); + * } + * + * static void + * _test_error_cb(void *data, Eio_File *handler, int error) + * { + * fprintf(stderr, "error: [%s]\n", strerror(error)); + * ecore_main_loop_quit(); + * } + * + * int + * main(int argc, char **argv) + * { + * Eio_File *cp; + * + * if (argc != 2) + * { + * fprintf(stderr, "eio_ls directory\n"); + * return -1; + * } + * + * ecore_init(); + * eio_init(); + * + * cp = eio_dir_stat_ls(argv[1], + * _test_filter_cb, + * _test_main_cb, + * _test_done_cb, + * _test_error_cb, + * NULL); + * + * ecore_main_loop_begin(); + * + * eio_shutdown(); + * ecore_shutdown(); + * + * return 0; + * } + * + * @endcode + */ + +/** + * @page tutorial_file_ls eio_file_ls() tutorial + * + * To use eio_file_ls(), you just need to define four callbacks: + * + * @li The filter callback, which allow or not a file to be seen + * by the main loop handler. This callback run in a separated thread. + * @li The main callback, which receive in the main loop all the file + * that are allowed by the filter. If you are updating a user interface + * it make sense to delay the insertion a little, so you get a chance + * to update the canvas for a bunch of file instead of one by one. + * @li The end callback, which is called in the main loop when the + * content of the directory has been correctly scanned and all the + * file notified to the main loop. + * @li The error callback, which is called if an error occured or + * if the listing was cancelled during it's run. You can then retrieve + * the error type as an errno error. + * + * Here is a simple example: + * + * @code + * #include + * #include + * + * static Eina_Bool + * _test_filter_cb(void *data, Eio_File *handler, const char *file) + * { + * fprintf(stderr, "ACCEPTING: %s\n", file); + * return EINA_TRUE; + * } + * + * static void + * _test_main_cb(void *data, Eio_File *handler, const char *file) + * { + * fprintf(stderr, "PROCESS: %s\n", file); + * } + * + * static void + * _test_done_cb(void *data, Eio_File *handler) + * { + * printf("ls done\n"); + * ecore_main_loop_quit(); + * } + * + * static void + * _test_error_cb(void *data, Eio_File *handler, int error) + * { + * fprintf(stderr, "error: [%s]\n", strerror(error)); + * ecore_main_loop_quit(); + * } + * + * int + * main(int argc, char **argv) + * { + * Eio_File *cp; + * + * if (argc != 2) + * { + * fprintf(stderr, "eio_ls directory\n"); + * return -1; + * } + * + * ecore_init(); + * eio_init(); + * + * cp = eio_file_ls(argv[1], + * _test_filter_cb, + * _test_main_cb, + * _test_done_cb, + * _test_error_cb, + * NULL); + * + * ecore_main_loop_begin(); + * + * eio_shutdown(); + * ecore_shutdown(); + * + * return 0; + * } + * + * @endcode + */ + +/** + * @page tutorial_monitor_add eio_monitor_add() tutorial + * + * To use eio_monitor_add(), you have to define callbacks + * for events declared by eio. + * Available events are : + * - EIO_MONITOR_FILE_CREATED + * - EIO_MONITOR_FILE_DELETED + * - EIO_MONITOR_FILE_MODIFIED + * - EIO_MONITOR_FILE_CLOSED + * - EIO_MONITOR_DIRECTORY_CREATED + * - EIO_MONITOR_DIRECTORY_DELETED + * - EIO_MONITOR_DIRECTORY_CLOSED + * - EIO_MONITOR_SELF_RENAME + * - EIO_MONITOR_SELF_DELETED + * + * As nothing is worth an example, here it is : + * @code + * #include + * #include + * #include + * + * void file_modified(void *data, int type, void *event) + * { + * const char *filename = (const char *)data; + * printf("file %s ", filename); + * if( type == EIO_MONITOR_FILE_MODIFIED ) + * printf("is being modified"); + * else if( type == EIO_MONITOR_FILE_CLOSED ) + * printf("is not more being modified"); + * else printf("got unexpected changes"); + * printf("\n"); + * } + * + * int main(int argc, char **argv) { + * Eio_Monitor *monitor = NULL, + * *monitor2 = NULL; + * eio_init(); + * const char *filename = eina_stringshare_add("/tmp/eio_notify_testfile"); + * + * monitor = eio_monitor_add(filename); + * ecore_event_handler_add(EIO_MONITOR_FILE_MODIFIED, (Ecore_Event_Handler_Cb)file_modified, filename); + * ecore_event_handler_add(EIO_MONITOR_FILE_CLOSED, (Ecore_Event_Handler_Cb)file_modified, filename); + * + * ecore_main_loop_begin(); + * eio_shutdown(); + * eina_stringshare_del(filename); + * } + * @endcode + * Build the example doing : + * @verbatim gcc -o tutorial_monitor_add tutorial_monitor_add.c `pkg-config --libs --cflags eio ecore ecore-file eina` + * then create the file /tmp/eio_notify_testfile : + * touch /tmp/eio_notify_testfile + * and launch tutorial_monitor_add, and in another terminal, write into /tmp/eio_notify_testfile, doing for example : + * echo "test" >> /tmp/eio_notify_testfile + * @endverbatim + */ + +/** + * @page tutorial_dir_direct_ls eio_dir_direct_ls() tutorial + * + * @li The filter callback, which allow or not a file to be seen + * by the main loop handler. This callback run in a separated thread. + * It also take care of getting a stat buffer needed by the main callback + * to display the file size. + * @li The main callback, which receive in the main loop all the file + * that are allowed by the filter. If you are updating a user interface + * it make sense to delay the insertion a little, so you get a chance + * to update the canvas for a bunch of file instead of one by one. + * @li The end callback, which is called in the main loop when the + * content of the directory has been correctly scanned and all the + * file notified to the main loop. + * @li The error callback, which is called if an error occured or + * if the listing was cancelled during it's run. You can then retrieve + * the error type as an errno error. + * + * Here is a simple example that implement a stupidly simple recursive ls that display file size: + * + * @code + * #include + * #include + * #include + * + * static Eina_Bool + * _test_filter_cb(void *data, Eio_File *handler, Eina_File_Direct_Info *info) + * { + * Eina_Stat *buffer; + * Eina_Bool isdir; + * + * isdir = info->type == EINA_FILE_DIR; + * + * buffer = malloc(sizeof (Eina_Stat)); + * if (eina_file_statat(eio_file_container_get(handler), info, buffer)) + * { + * free(buffer); + * return EINA_FALSE; + * } + * + * if (!isdir && info->type == EINA_FILE_DIR) + * { + * struct stat st; + * if (lstat(info->path, &st) == 0) + * { + * if (S_ISLNK(st.st_mode)) + * info->type = EINA_FILE_LNK; + * } + * } + * + * eio_file_associate_direct_add(handler, "stat", buffer, free); + * fprintf(stdout, "ACCEPTING: %s\n", info->path); + * return EINA_TRUE; + * } + * + * static void + * _test_main_cb(void *data, Eio_File *handler, const Eina_File_Direct_Info *info) + * { + * struct stat *buffer; + * + * buffer = eio_file_associate_find(handler, "stat"); + * fprintf(stdout, "PROCESS: %s of size %li\n", info->path, buffer->st_size); + * } + * + * static void + * _test_done_cb(void *data, Eio_File *handler) + * { + * printf("ls done\n"); + * ecore_main_loop_quit(); + * } + * + * static void + * _test_error_cb(void *data, Eio_File *handler, int error) + * { + * fprintf(stdout, "error: [%s]\n", strerror(error)); + * ecore_main_loop_quit(); + * } + * + * int + * main(int argc, char **argv) + * { + * Eio_File *cp; + * + * if (argc != 2) + * { + * fprintf(stdout, "eio_ls directory\n"); + * return -1; + * } + * + * ecore_init(); + * eio_init(); + * + * cp = eio_dir_direct_ls(argv[1], + * _test_filter_cb, + * _test_main_cb, + * _test_done_cb, + * _test_error_cb, + * NULL); + * + * ecore_main_loop_begin(); + * + * eio_shutdown(); + * ecore_shutdown(); + * + * return 0; + * } + * @endcode + */ diff --git a/doc/foot.html b/doc/foot.html new file mode 100644 index 0000000..78ef911 --- /dev/null +++ b/doc/foot.html @@ -0,0 +1,19 @@ + +
+ + + + + + + + + + + diff --git a/doc/head.html b/doc/head.html new file mode 100644 index 0000000..b0f0a2c --- /dev/null +++ b/doc/head.html @@ -0,0 +1,67 @@ + + + $title + + + + + + + + + + + + + + +
+ + + +
+
diff --git a/doc/img/e.png b/doc/img/e.png new file mode 100644 index 0000000000000000000000000000000000000000..b3884a5cbca7bce5747eb3b8a92145d60511a718 GIT binary patch literal 3825 zcmW-k2|UyPAIGQMS98Ry6)m}iA@`NJZE_o#Ovc73e^-^QHU$G0h_3|cuDljd5QbT#Je?6pNPP^G($^aTorE>q=yral%n2Rktlk|u< zB6SbBG`&ZF=tG%tj9|RLw-;=+A0K(VYgY{_m@_Mu;#9$;A9&jo($nUG3m{pPG9sKJ z)-SrEJ!oZpgRkTbv#N2w?Avv1g`*hj3@X!Cn+Jh2Ml;^V7@mz6b|Fo-YFT&Oc=qw1 z@}>V_jJMQ>kyo}tc5CX?e65}5iLW`a*?=JPI$Jx)*JdpOpdFk$7LNZlSowU@cr#Mjx)>#Vh2qRYMG@4%U~V=*(;bxq6%o;REM)$>G`C7nd~m&p*#P>~ zXHur`Yquq~Y&12(1U{S4izUj!VqeX6#jVc9i4wfL*s)~-o}QjXMEK_BCOa2bR1e|w zfOiwc9TpT4;xRu`3f2tu^&xUXTv-ZkyvdBZz~6YF9A*}l+0tzM1w6ihdTKaGCcM-b zM}+kR##h<)t_vDPGSvAu;zhryW3SGaF8dM)M|gO64tMi+Iy@ydmbFeUae-c2{QNoG z(9m#bJ|Lb-MPIsvICAtT6Qr%J&FlJgLwoz<%m(`4rx$N)fyA(+zm0CXPABZ`Y;G;L z{_bdyy$#F#KH(XXsO3Jb1Q#zc1fq{*U zjYV~JP>U?NSCL2Ad=K{iTFJ6FGWAV|A0&YtJIM(N3JQvei!+~p$aC|>Dl6&yL|#Xg zIX+2Weg&eas2K77JvQjh9i*O~D5!_YojcEE+(AXktE#$w{w%LP_%H5M=b04kBWh}D zxc2O9VLyNW)gECtF*P+|5T~J=o2apg$$#_(d-_h^TCnHtq71c!2zRWxWDpjn!_UuO zcWv<0kxLtcNl8iN)zxTQTLC2}o9m(byTL;$JWs}{A3oS^ZEvS;Z{E>Cp-_rSN|AlCExY6x%V{lP3aGQ&Z}<7hzfQ zF07zj10`OsC@iK}tTCCaB&2|+E-(9l0(Hy>@X!C-*+HtR-ujI2c$AdYyXh^~)F4Il zzzMlLC8a)YPnWbhjIFPa%gD$GmE?PCduwZ^?eCPKudkxBi;LOH8N8LwW`;LSS$4%) zx?ENsdRA0Kgd_bexl4mJQOGB;;>g}!^1**?gy$7$wPR|Ei zVs8!%jpMNr88)kWN^?ogde$9cWo2b)X&FJ2;y!k)F9OgLp&JTI(cO{q^YfcwF#H{j z%mHD&8k`>k(lj9Q-C;Og+VS&=mg%exwn**okO~FI#6R7i^cR~amJZy`{L_nl_Uzd# zP+riFoNM<}Q<iF240XUkipnh)?rRKXHCsH%<~~eP9Nw zkqau%sz*Z!{@*$FcNP?o@?cZr%EaUjMedC|I-tV!fV+9RVQ_4jZKfCbIfH;Kg45E_jJnnwJDq^pApCdwVgPKmHB z!=6@FPNzCr)C6drgvA1wG8MJ9x;!~AS&DhwVSc;3B#qv%<6L7Hx)0{h+mg+0 z0jqK$SZNPm{q3QtspPPKfBq{eiS~+YJS!pb6?`OSoRqamr_%>N_q^qN00y+O`IQf2 z+ONq@jb3~&ch@XXS3^S)t+$ts^fgp^l*D2hS>*bVDk_42(C2Bz#jeZyq=~0Iw_8tY z=KJ_03RcSYhZI2ZA^5$2n^Z zhKHkI8AsB4C}Cb-U2XZaezlWJK@9Yhu?X!asz+tBKS$Zr%IdX3`!1>nqM47)$jG={ z6Hw*j?B(e@8paOM)YQD_>MGBrf)C%jMf%)G{A_Ab!GaWc-rAa)nHj@)ozmsgEFfWL zXIE5Pd(7NL^`S8bMGS3ZguyK+PiESq78xme#+H`U#qGE0lGfJNvkkwHO>4CJD>xwo z1A{jM11ylm>2^1Vo*e(Pl1LDQ5Ws)HygDLK6i)xZ|&>dfsOPKeXm+M(}+hAe4X z6^(1_>#6teN95%pc2{4Es^8g=`ug?jBeWA}$-@!V(E(v)V{=!8L18fV@bGXsTtjrf znx^KxYlUG#U=E@&U;>bLx5xnj0W$+?(|PNsIb8382bo;|XlLL`xUQxqTtr0V=kjuF zbF&(t;zeg?&f;NqvRMLSa&mHZZZ58_PO-bU7l}ggM@B{}!jl?)gFFKHeR&Zq0D+2% zretIY!nj${CML!8^?U#T%DQSrV~56cXy{^gjJZ5-NJt2yBl4*FtzUx9&dx=n^A{Z* z<3>hoGP1Hd>2zVBB+57`HanY674K}2^S*xF8jnx@@#E^^RNIN1oSaWB#cMgJ*Otw*rB&I6XkW|M$G6uvyt`6=4Q|K`kZ_71o=n5$YD92 zJ{1C@Q+zl8Tt!rSyB;@d6scf;|L*S2Lai5x)ZLRPtfZ|?1=~Oy8x#I6Pp+)3br$G^ z42_NbX`h$s5(7DsmzRH{J7@@G0_>a>lRU=kBQ^b#^fF9~Kp@mz9e@J|CF~Z; z=i}oO1g5^dRdnUai@D1~BN_7E-_c)hH&#LIcW)}f^hZ^u!v4CB{}Fsm_VV)Tm@5qD zjdcf6#)5f&1{ecDqyO64P9`KI#K*@&x)g(!n&@@JQ3+sRI=q{XKyeVzcDKRmK@VQGJz^%tG zO*DH_jWQ#&1@Sat zu45x^o;XwQrjLI%y5Cr6|6eo|$`MN}mI6S}%?;gTi+K0Wd__BDY6`#c=MU}03j`ox z^qWHiar!iqj*br68Cc1Nu2gRuM_H0oc5HR5WMzw#YBJ+Wsm%9p=9#t=@;89dymqau zKP+D>F!{yAmoIV_{<5;N^>;SCQP(Ui607kFI%@i(8yU7p?}*InZkocy4qt5dWs-8? zfgi_Qz*j9%K=LhN|IXK+Sz20ZXd>1-)p-pgacy h3 { + margin-top: 0; +} +.directory p { + margin: 0px; + white-space: nowrap; +} +.directory div { + display: none; + margin: 0px; +} +.directory img { + vertical-align: -30%; +} +/* these are for tree view when not used as main index */ +.directory-alt { + font-size: 100%; + font-weight: bold; +} +.directory-alt h3 { + margin: 0px; + margin-top: 1em; + font-size: 11pt; +} +.directory-alt > h3 { + margin-top: 0; +} +.directory-alt p { + margin: 0px; + white-space: nowrap; +} +.directory-alt div { + display: none; + margin: 0px; +} +.directory-alt img { + vertical-align: -30%; +} + diff --git a/doc/img/foot_bg.png b/doc/img/foot_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..b24f3a48b4e076b88cf1e802b46087ffbb3fabd5 GIT binary patch literal 173 zcmeAS@N?(olHy`uVBq!ia0vp^j6iJ9!3HE1Qx}DR1d4;)ofy`glX(f`uqAoByD;nl zL8a%*b^=8>3p^r=85p>QL70(Y)*K0-AbW|YuPgga7CvEi%SZD}LFVdux;TbNTu#2R zIsJTn+kYTPulo1Ll3AD;2!xfDmD#wLvj}>v&@k-CVP=T_%(cphxuXQAk-^i|&t;uc GLK6Ub>Mc;VkfoEM{Qf z76xHPhFNnYfP(BLp1!W^H+WcuRXD>A=l%i;Wq7(chG?8W+i%Esz<`6f_y7NWHH!5o z63R1{^0cb0vMSkFaE_%x<+7O{*?Xs&Ff%xKT5jO&GtAqcqoa~}b>qg&H07ky z617wnX2HUfTT*8{k002J-1^@s6XaB>y00001b5ch_0Itp) z=>Px#32;bRa{vGf6951U69E94oEQKA00(qQO+^RT3Fc5TrKj#zpOzs?z2=A0p@aw&u*pMn|G)ug+?Vh;0+zHe5dVLoF=!DBW&zJ?E zp99|S_j0@4%Io#|xG+sqdB5NP{rn5Cj%O+78UIn|DpKcsK9>`B2V6JsOB3oD&r;4a z{-e%Sw9ela{A&{jdu5*U-Tgr1~ zQc-ZvZCmQQrCnTG+COg8zWQ3Lv1sjNIKQPlR|Xsq_}(oT0MbDS91lPg3>xeBFKokrh3I+f~!N36>5GNtP zFb=56FWNP#oK=?bNEQ~!rtXW9X1GX=k~FL`OjOeF$R)LGB-wAZi(5xddgID^{pUl5 z$!2zVWE!iC5c%CAFL=jfl{TW1M$7Wjcr9z}SyPKmlC20r0B}G6Q80PClsJ^eQ9Rdb zuHflIJ5saoBdvW)J5o7`LrQ$sb0li*FS@pt^@$vLe#kJ^<1ntHwKLacEE8!V_VYY{ z^jk0Fa-9o0ILfhhgnDcg*`~%yk#UNgFLkMLQ1xp&>oHLMt>=krgKLZ9aoj&)eVyWk z+VI9yb#%knV zBgOT1iW^1q->g9a$6utrxv^4Ql-s5#yS%xS5>LwpJyaYZ1w-06F426k%%gi2p;YTL zn*Zi$*TU&q<}Gq{z5F%GPa}Dt9$}k233)sorIb>h&nNZ+VE-)`LNtIN1b_p=0f8Pk zSwvore6GJZg3A%uh&UU`%8A$z3ApNcvGym`^9BW5y;mkO7OVYaI#wj=im2;bzSt*w z8j*3rXhhk-tiA%ik?Y6P7yM_$}>d^Cl%aa8a!%A!J=gv)gqCjA%RAmjShY zk&jin$jBj)wrhPzE#o_v^@kLW;DnK~k;Uxogc+{8mlL+=3tKP%4hR4$2Lynj z95C}RO)LJ$<@I?2i7h|tH#%lcU&}tk-(ol0<1_foFDdWsgqjV%=7cRA;M<%KLNw4f z2!R6vT{&RuTk7799C>JZ4;!>{ThW;;ZOYD_SA%VO2ZR&C3B68;Eg1NXEf@e0gaF^` zfS#=57JO;X{zkCF($|*uL^8|wn48N;fkQ7R9I3CpA0+QRH%LYRy5b)R!`g7p731Il O0000002J-1^@s6XaB>y00001b5ch_0Itp) z=>Px#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOZ7 z02vXk7GypE01Qq^L_t(|+U;H2a^tuXlN0^d3_%Mmt|S*_xtkl^78E$bGzMsW@O^E@B1-+ z=cVS*V0UU7pRP@U;-OvwL>DMu{R0abUb{x*}m z@B4oYcs3YunesE)Z}j8zrzRR*2Qx`$S!kAh|3>CJWrAG*GLX2Fe)h(rzjg+&sxS80 zcbMC=ef;e}EdiJ(`3%q$9hv{=thAZ zpj~02U6We1r_3JuyTgdH571c<%rJWAn5)2<+gWe7+X22Y2-~(nHi`f1_)l)SMgf#Jj8JEL5q`z9;(>xI3~8m`p)OaYtLX&lh0g*>LDJVk86(i z=kyov4*{0}DZk>FF#wNa4hGB@`||R#3~-LWl@Egki#?GMP;Am(US5vA=z0`0WFWFJQh<&3f+l(2_hZcBJtII5vSC1p*H_JX1~&q0d?50; z9+i-IF}K_8xX5gx6*IWER<=amoW`jd#YBk4T_A$cGxKdSUi@`qKv&aoVEA{nDHR+_2yWJasfY5BO>R2DM#*|ftn40E*Ih_;(Ua&ul4 zh-X-Wv9g=*`;3Z+YsQ>oJK&jZ#~tem*arhL|A(2liun{cE3;aeebuf@K z<{@$WJbN5uKxH0Oawoia%4=cqI_8 z@atR?uKZ`Gy>$Q&W$P$}#1#?lnW*=w=zGSDRyFp{|IueF%YZXbRXH<9LGqa_H^Z!7wXo>3 z0MudBnQQ0*%}I+r0dV+$PEer|sA_fDtl!x6!Mf(HQlMPz{9mChbjxs8KNzZ?j@kVX zgyaHqPMa_gx$0w97CQr!*}zAspBlr?S!q5>pR8ll>^(m=-luk6H5 zDh7cN0W_QIN=oGd$WiU)+P0b)Cm_l9kc;^F`dn2}Y{MA~M;^u`amch*0t9wHNZg== zu^-YfqhOqGZk!l}q47e8q$++sBw10+s!U&gS}Jt~@;woIxD4j_gkumL)pBM4XDLGr z0+AwHS*WfFjbnr)S`}+4Kr$r_(h)Ap|28Mea;%P1kD_P?{qED|RA;X6o!p2zi#;p$ zR7)A$dpaW?=mrNJ?W2;dq2th8uWxT}%iG)A^85GiCw~o@(#&SezeC%6Ak)sycgkj& zQI%6)ol~t%QGK9ATuK92N!ne1u>(3MO~w2;<>x7LkNVBh{3jEfI~@ZaPl&oM1(LDX zjI*Ag3M|wruZ|)&uem_Jsro$rj`x;>Af}(p>SA>ton5Xf-%SBMUq1o}`mNO36}x6% z@u?J-pVqj@1^FS2$+8HMu~S^^l-WWplxI)0s)#6)sQOdx24gKZkaEnFYgUz_Tbb4T zV6c^RNXecVUrG9qkGO5yzdj&iKnFyX%v`O-je(Cku9B~-XuY$&nv;N^O$2ur!*}w2 zGr2vc7Ds@sa(WDi$~+%w7{@eJ;eWLtx&l{6ZIh$*D$(7Y9M*RAV7R$C_x-Go=a%do zU{wj_$|@kH{ZI)(QY;r>in&mpPURU{Uad3nPKu=pRMgs%%G_65ZOjH2-F8(U87S_y zB;BCHWzdx^*;AE?Gfby^M+N+uw90JRuUkc_62LP6R3KDr(=Det<+C%)Sp7cofR!2R zfUC3rN@Xgl6pdRptk}?DRkt)Y6GU`O>umpyFX!YVs|t?`z5{?NeUNj5SAZ~AL0I{! z+6JWS<2jM@%yx8DiE^fnJDY&6f}Jj)oCLFz%w~W-7%-+=DmJQ2Xom?ExLDe!5-4;{ zrkm2K7HoBZa5kdt_EkltGmO_U&FmUimcwBa*qpdhwWTf#XnrKCCYs)P=%?EVbX z&6;N?rQ$52ciGXc>^%8^c})lt3!ojU6wsW{6x%WLdM&yE11b~CQYGE=OeJ)<5VW9y=&YuLAfe%Wnt==upw4Z%rPz^ADi2AcH>mlm8?>U_3Y8dOv1O4 zV>yC_$}i0K5rw?y;c>RjW%Bt-w4gwQ9wxN=DQW{<|6zhrfWfx7jp>?kakty;!{leS zLyF(rcHRm&GiSWMthmlMu8QMIhR;~{3KOihaf^V-(k2Bu1pNFEDW46M<`DZaJs%S^ zD0d*@=!k*`5c6b5hGIcU25)3LBw|(ivMljO=4*%&BKQ=r)OKtvDn@MT1RK?Et|-`Z zTngovW)Lfrn~6iQc6^_S%FQ7vYp`wGvcA8+KV4jwNX7TrKgt6)CM|yXVU~0;m2AAZ z$b@<0Z8rGmxaun=DydnV@JcVpHWqhsglZT044iyETcyS}V2|@r$*~aQWf13kir_}T z&tv-(1*4o9(g#N0im7WEaGCfZABR?kjnAY1>8xN=B|ZdvM?TLa_y~M%WdcR~%>2gr zLP}&LG(~0^EeOl!xi#d7BiCFXL5M2Dv6Kv|TEri;YkLH7J|})weg8xTVYNQk*}F!q zVC(LK*AXzNh#8r$9N=|CqZv?WXN;MYjaqu39=c|yS9zjUX=T%jZs!oe`3P82x zoCIb8gsR3f`)rcc z&IiudZ)HD{0aMjs&nzpb#0-vh4&}`l=o~;fU~}GACC856SOSnmxRr2J`Gv?obbyLX zbru_-pRNQ;=?7<+PAQ1kmlLA2iOYnuz^eocGZAui%=-TRF25GkVKk*?VLM7WBGYPB zT*tpuphVY?L>99zcgqh{8?J&32Rv?+%)Z_WCB$d`hC#@mKYy$$hzm4z911e3T@BQE z6}a5Q^z2GI$3(jeiH2?d26Vp6Zr1N{77{V3le;970pcooz1rBP zTCCqm&A0&u`_5tKoG#cZcARCvr+{+b_xPx#24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOZ8 z6%`IG`XD&~00I3;L_t(o!^Kz8j>8}fODg_+AF{uksuh}hxC0rJP`W$mkkHl^jB%XM z>f`Y+`Dtd>`gxwMmr`2KIk$cshdiH8N#}XW6$o}5WA?p%5)sKc%eHO9fR!#HlFUqU z&XQ6Z1~3DUmCHm#rjx?$lu|lm24QA+Eh4g2CJ}X<;QbGo;J_$CohD|s1Tu}z3KIrH zRtpQ8-Z|UyQP4caCB~&Z3QG0mMzcQLYIcQ!(sFW-xf9knF@|(?iY~XAOhHzd%#8OD2m>x}XSSsVf@;^obfpX48<@ZgFF$M4@xtjbM#B=Ojp!9yfFNKXj22K7STvD?00000NkvXXu0mjfB76)l literal 0 HcmV?d00001 diff --git a/doc/img/menu_bg_unsel.png b/doc/img/menu_bg_unsel.png new file mode 100644 index 0000000000000000000000000000000000000000..50e5fd8d3d17114bc71e14c483532f2c082920b2 GIT binary patch literal 1596 zcmV-C2E+M@P)002J-1^@s6XaB>y00001b5ch_0Itp) z=>Px#24YJ`L;wH)0002_L%V+f000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2iOZ6 z5FZU~yaYY~00q2BL_t(|+U;H2a;q>5blUuRzqvD+7VvpFWE>%_)?7k5*?npguqAmd z8(5Uf*Vk7qf^ZV9(=;gx!g&NNrIcY9%E!ltq9Ht=fVI{#3`4nIuZo7C3@E%I0mpGH z+6xLIpzyv+um~ueb`dgXz*=j$TrP@=0TUO+Zl@)sQ3vT-lF8GjhNS)Y)Np5NBKI{~L@T3m#*2iTKp zt@p;JX@cbN4E2Ix|BjCFg536j+O}xz_u6Q`^V-S$v$poy&cxQ*Y0r;rMq}sMi^c@` z(Y9kbHGfVm!D!}MMH6RQOQ=PVd8HOe5K@dz0av&_)W-mG0@FVnX-$jszG6Cpd6iG4)S zD4R33W^wegr6p&!^ui1{3`424F0w(E#-nu32HZMgjcogm$jB1kn}usg#Vp4?lQGIP zmJDq6inbT557~swV%+wP_%pYAzYQ~vV>tL(hik9?P_~PVkL=oF50e?tN^s;oR77r% zlT|&VC}Ga0&tEJ%k7- zoJv4FMiNe2g8%YGh@d4{5VmDN2~q_u!NU6zP)o2N0s>_EwNi4;;4^G#zyC`L>8-YI zIsZ<;Sq-zMv%STs5t%X@*w0xZXGHX=S58L)URT4u^Pb?4-gC!@j zGZO+Nz0VPNkPS1cMpr9pK zPzLm{wVGyxy%obpDUi2TLEY1CBu?G4a_w4M*7W_50a2rjQkgL}dUVxOnilo5_XJ|? z^0b6KgUQ;2DyO!8Gi7vpi4|3GMVi2@-Nh0d2`yX4qE34Ty0;9h7ucR!#o2^lg6|D> zq>N@KDl1M!v148j=!p*!BwK!Xg({IeZ9%}cIAvzMSJ)Ae5UHkn2oMDWN!z_bn~X9f z@-5QES=A0wM|(C$1t(DkMz$~$G8#J+SMOZ5Dyv8A`w~27zqUXna*hph7O3bmD~Gp^ z*;fa=*%<}bla(WZrnkg+@^mC+kFs@kF8aj)Hk+cY4=Q!sYBVE3usz00Cd{g}$bgX+ zEs`2}PM|AlPwbhc>#U3~dKV?KArhvt%U4th9!;L?oeXA`K|g&EO%g=b=rg7ws`Z0W zfG^}&b8$*k*B4={a+xJocKjaIK(oCqTOT@;wzHCX)@Jr%Fnd8LdMj})ftln4_kht_ z?hOuGQ#w0_X^UxNi{yO`dG|z5aq*tmGIh6m-ucZ4$E=q33^;eTcR-I+1i!M{_!a$H z+wPGv{WJp#!l6$>RG?fqm4Ls$zapS;ZU)p6ES#PJ^<&F|2q=hvg78!V{`~xifWmnM uoCT@+p&H=~TxzX#9LMtc`Kf3KPscx4r4cOw-wj9r0000 + + + + diff --git a/eio.spec.in b/eio.spec.in new file mode 100644 index 0000000..280981e --- /dev/null +++ b/eio.spec.in @@ -0,0 +1,60 @@ +%{!?_rel:%{expand:%%global _rel 0.enl%{?dist}}} +%define _missing_doc_files_terminate_build 0 + +Summary: Enlightenment Input/Output Library +Name: @PACKAGE@ +Version: @VERSION@ +Release: %{_rel} +License: LGPLv2.1 +Group: System Environment/Libraries +Source: http://download.enlightenment.org/releases/%{name}-%{version}.tar.gz +Packager: %{?_packager:%{_packager}}%{!?_packager:Michael Jennings } +Vendor: %{?_vendorinfo:%{_vendorinfo}}%{!?_vendorinfo:The Enlightenment Project (http://www.enlightenment.org/)} +Distribution: %{?_distribution:%{_distribution}}%{!?_distribution:%{_vendor}} +URL: http://www.enlightenment.org/ +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description +Enlightenment input/output library + +%package devel +Summary: EIO headers, static libraries, documentation and test programs +Group: System Environment/Libraries +Requires: %{name} = %{version} + +%description devel +Headers, static libraries, test programs and documentation for EIO + +%prep +%setup -q + +%build +%{configure} --prefix=%{_prefix} +%{__make} %{?_smp_mflags} %{?mflags} + +%install +%{__make} %{?mflags_install} DESTDIR=$RPM_BUILD_ROOT install + +%clean +test "x$RPM_BUILD_ROOT" != "x/" && rm -rf $RPM_BUILD_ROOT + +%post +/sbin/ldconfig + +%postun +/sbin/ldconfig + +%files +%defattr(-, root, root) +%doc AUTHORS COPYING README +%{_libdir}/*.so.* + +%files devel +%defattr(-, root, root) +%{_includedir}/* +%{_libdir}/*.a +%{_libdir}/*.so +%{_libdir}/*.la +%{_libdir}/pkgconfig/* + +%changelog diff --git a/m4/efl_examples.m4 b/m4/efl_examples.m4 new file mode 100644 index 0000000..2a809ad --- /dev/null +++ b/m4/efl_examples.m4 @@ -0,0 +1,63 @@ +dnl Copyright (C) 2008 Vincent Torri +dnl That code is public domain and can be freely used or copied. + +dnl Macro that check if building examples is wanted. + +dnl Usage: EFL_CHECK_BUILD_EXAMPLES([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Defines the automake conditionnal EFL_ENABLE_BUILD_EXAMPLES + +AC_DEFUN([EFL_CHECK_BUILD_EXAMPLES], +[ + +dnl configure option + +AC_ARG_ENABLE([build-examples], + [AC_HELP_STRING([--enable-build-examples], [enable building examples @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_build_examples="yes" + else + _efl_enable_build_examples="no" + fi + ], + [_efl_enable_build_examples="no"]) + +AC_MSG_CHECKING([whether examples are built]) +AC_MSG_RESULT([${_efl_enable_build_examples}]) + +AM_CONDITIONAL(EFL_BUILD_EXAMPLES, test "x${_efl_enable_build_examples}" = "xyes") + +AS_IF([test "x$_efl_enable_build_examples" = "xyes"], [$1], [$2]) +]) + + +dnl Macro that check if installing examples is wanted. + +dnl Usage: EFL_CHECK_INSTALL_EXAMPLES([ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]) +dnl Defines the automake conditionnal EFL_ENABLE_INSTALL_EXAMPLES + +AC_DEFUN([EFL_CHECK_INSTALL_EXAMPLES], +[ + +dnl configure option + +AC_ARG_ENABLE([install-examples], + [AC_HELP_STRING([--enable-install-examples], [enable installing example source files @<:@default=disabled@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_install_examples="yes" + else + _efl_enable_install_examples="no" + fi + ], + [_efl_enable_install_examples="no"]) + +AC_MSG_CHECKING([whether examples are installed]) +AC_MSG_RESULT([${_efl_enable_install_examples}]) + +AM_CONDITIONAL(EFL_INSTALL_EXAMPLES, test "x${_efl_enable_install_examples}" = "xyes") + +AS_IF([test "x$_efl_enable_install_examples" = "xyes"], [$1], [$2]) +]) + +dnl End of efl_examples.m4 diff --git a/m4/efl_threads.m4 b/m4/efl_threads.m4 new file mode 100644 index 0000000..33d15a3 --- /dev/null +++ b/m4/efl_threads.m4 @@ -0,0 +1,206 @@ +dnl Copyright (C) 2010 Vincent Torri +dnl rwlock code added by Mike Blumenkrantz +dnl This code is public domain and can be freely used or copied. + +dnl Macro that check if POSIX or Win32 threads library is available or not. + +dnl Usage: EFL_CHECK_THREADS(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Call AC_SUBST(EFL_PTHREAD_CFLAGS) +dnl Call AC_SUBST(EFL_PTHREAD_LIBS) +dnl Defines EFL_HAVE_POSIX_THREADS or EFL_HAVE_WIN32_THREADS, and EFL_HAVE_THREADS + +AC_DEFUN([EFL_CHECK_THREADS], +[ + +dnl configure option + +AC_ARG_ENABLE([posix-threads], + [AC_HELP_STRING([--disable-posix-threads], [enable POSIX threads code @<:@default=auto@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_posix_threads="yes" + else + _efl_enable_posix_threads="no" + fi + ], + [_efl_enable_posix_threads="auto"]) + +AC_MSG_CHECKING([whether to build POSIX threads code]) +AC_MSG_RESULT([${_efl_enable_posix_threads}]) + +AC_ARG_ENABLE([win32-threads], + [AC_HELP_STRING([--disable-win32-threads], [enable Win32 threads code @<:@default=no@:>@])], + [ + if test "x${enableval}" = "xyes" ; then + _efl_enable_win32_threads="yes" + else + _efl_enable_win32_threads="no" + fi + ], + [_efl_enable_win32_threads="no"]) + +AC_MSG_CHECKING([whether to build Windows threads code]) +AC_MSG_RESULT([${_efl_enable_win32_threads}]) + +dnl +dnl * no + no +dnl * yes + no : win32: error, other : pthread +dnl * yes + yes : win32 : wthread, other : pthread +dnl * no + yes : win32 : wthread, other : error + +if test "x${_efl_enable_posix_threads}" = "xyes" && test "x${_efl_enable_win32_threads}" = "xyes" ; then + case "$host_os" in + mingw*) + _efl_enable_posix_threads=no + ;; + *) + _efl_enable_win32_threads=no + ;; + esac +fi + +if test "x${_efl_enable_win32_threads}" = "xyes" ; then + case "$host_os" in + mingw*) + ;; + *) + AC_MSG_ERROR([Win32 threads support requested but non Windows system found.]) + ;; + esac +fi + +if test "x${_efl_enable_posix_threads}" = "xyes" ; then + case "$host_os" in + mingw*) + AC_MSG_ERROR([POSIX threads support requested but Windows system found.]) + ;; + *) + ;; + esac +fi + +dnl check if the compiler supports POSIX threads + +case "$host_os" in + mingw*) + ;; + solaris*) + _efl_threads_cflags="-mt" + _efl_threads_libs="-mt" + ;; + *) + _efl_threads_cflags="-pthread" + _efl_threads_libs="-pthread" + ;; +esac + +_efl_have_posix_threads="no" +_efl_have_win32_threads="no" + +if test "x${_efl_enable_posix_threads}" = "xyes" || test "x${_efl_enable_posix_threads}" = "xauto" ; then + + SAVE_CFLAGS=${CFLAGS} + CFLAGS="${CFLAGS} ${_efl_threads_cflags}" + SAVE_LIBS=${LIBS} + LIBS="${LIBS} ${_efl_threads_libs}" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], + [[ +pthread_t id; +id = pthread_self(); + ]])], + [_efl_have_posix_threads="yes"], + [_efl_have_posix_threads="no"]) + CFLAGS=${SAVE_CFLAGS} + LIBS=${SAVE_LIBS} + +fi + +AC_MSG_CHECKING([whether system support POSIX threads]) +AC_MSG_RESULT([${_efl_have_posix_threads}]) +if test "$x{_efl_enable_posix_threads}" = "xyes" && test "x${_efl_have_posix_threads}" = "xno"; then + AC_MSG_ERROR([POSIX threads support requested but not found.]) +fi + +EFL_PTHREAD_CFLAGS="" +EFL_PTHREAD_LIBS="" +if test "x${_efl_have_posix_threads}" = "xyes" ; then + EFL_PTHREAD_CFLAGS=${_efl_threads_cflags} + EFL_PTHREAD_LIBS=${_efl_threads_libs} +fi + +AC_SUBST(EFL_PTHREAD_CFLAGS) +AC_SUBST(EFL_PTHREAD_LIBS) + +_efl_enable_debug_threads="no" +AC_ARG_ENABLE([debug-threads], + [AC_HELP_STRING([--enable-debug-threads], [disable assert when you forgot to call eina_threads_init])], + [_efl_enable_debug_threads="${enableval}"]) + +have_debug_threads="no" +if test "x${_efl_have_posix_threads}" = "xyes" -a "x${_efl_enable_debug_threads}" = "xyes"; then + have_debug_threads="yes" + AC_DEFINE([EFL_DEBUG_THREADS], [1], [Assert when forgot to call eina_threads_init]) +fi + +if test "x${_efl_have_posix_threads}" = "xyes" ; then + AC_DEFINE([EFL_HAVE_POSIX_THREADS], [1], [Define to mention that POSIX threads are supported]) +fi + +if test "x${_efl_enable_win32_threads}" = "xyes" ; then + _efl_have_win32_threads="yes" + AC_DEFINE([EFL_HAVE_WIN32_THREADS], [1], [Define to mention that Win32 threads are supported]) +fi + +if test "x${_efl_have_posix_threads}" = "xyes" || test "x${_efl_have_win32_threads}" = "xyes" ; then + AC_DEFINE([EFL_HAVE_THREADS], [1], [Define to mention that POSIX or Win32 threads are supported]) +fi + +AS_IF([test "x$_efl_have_posix_threads" = "xyes" || test "x$_efl_have_win32_threads" = "xyes"], [$1], [$2]) +]) + +dnl Usage: EFL_CHECK_SPINLOCK(ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]) +dnl Defines EFL_HAVE_POSIX_THREADS_SPINLOCK +AC_DEFUN([EFL_CHECK_SPINLOCK], +[ + +dnl check if the compiler supports pthreads spinlock + +_efl_have_posix_threads_spinlock="no" + +if test "x${_efl_have_posix_threads}" = "xyes" ; then + + SAVE_CFLAGS=${CFLAGS} + CFLAGS="${CFLAGS} ${EFL_PTHREAD_CFLAGS}" + SAVE_LIBS=${LIBS} + LIBS="${LIBS} ${EFL_PTHREAD_LIBS}" + AC_LINK_IFELSE( + [AC_LANG_PROGRAM([[ +#include + ]], + [[ +pthread_spinlock_t lock; +int res; +res = pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE); + ]])], + [_efl_have_posix_threads_spinlock="yes"], + [_efl_have_posix_threads_spinlock="no"]) + CFLAGS=${SAVE_CFLAGS} + LIBS=${SAVE_LIBS} + +fi + +AC_MSG_CHECKING([whether to build POSIX threads spinlock code]) +AC_MSG_RESULT([${_efl_have_posix_threads_spinlock}]) +if test "x${_efl_enable_posix_threads}" = "xyes" && test "x${_efl_have_posix_threads_spinlock}" = "xno" ; then + AC_MSG_WARN([POSIX threads support requested but spinlocks are not supported]) +fi + +if test "x${_efl_have_posix_threads_spinlock}" = "xyes" ; then + AC_DEFINE([EFL_HAVE_POSIX_THREADS_SPINLOCK], [1], [Define to mention that POSIX threads spinlocks are supported]) +fi +AS_IF([test "x$_efl_have_posix_threads_spinlock" = "xyes"], [$1], [$2]) +]) + diff --git a/m4/eio_check_options.m4 b/m4/eio_check_options.m4 new file mode 100644 index 0000000..1d5e3f4 --- /dev/null +++ b/m4/eio_check_options.m4 @@ -0,0 +1,86 @@ +dnl use: EIO_CHECK_INOTIFY(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([EIO_CHECK_INOTIFY], +[ +_eio_want_inotify=$1 +_eio_have_inotify="no" + +dnl We need to check if the right inotify version is accessible +_eio_want_inotify="yes" +AC_ARG_ENABLE(inotify, + [AC_HELP_STRING([--disable-inotify], [disable inotify])], + [ + if test "x${enableval}" = "xyes" ; then + _eio_want_inotify="yes" + else + _eio_want_inotify="no" + fi + ]) + +AC_MSG_CHECKING(whether inotify is to be used for filemonitoring) +AC_MSG_RESULT($_eio_want_inotify) + +dnl It is hard to find a good test on how to check the correct +dnl inotify version. They changed the headers a lot. +dnl in kernel 2.6.13 __NR_inotify_init was added to the defined syscalls +dnl in asm/unistd.h and IN_MOVE_SELF was added to linux/inotify.h +dnl so with this check you need a very new kernel and kernel-headers! + +if test "x${_eio_want_inotify}" = "xyes" ; then + AC_CHECK_LIB([c], [inotify_init], + [ + AC_DEFINE(HAVE_INOTIFY, 1, [ File monitoring with Inotify ]) + AC_DEFINE(HAVE_SYS_INOTIFY, 1, [ File monitoring with Inotify - sys/inotify.h ]) + _eio_have_inotify="yes" + ], + [ + AC_TRY_COMPILE( + [ + #include + #include + ], + [int a = __NR_inotify_init; int b = IN_MOVE_SELF;], + [ + AC_DEFINE([HAVE_INOTIFY], [1], [ File monitoring with Inotify ]) + _eio_have_inotify="yes" + ], + [_eio_have_inotify="no"]) + ]) +fi + +if test "x$_eio_have_inotify" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) + +dnl use: EIO_CHECK_NOTIFY_WIN32(default-enabled[, ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]]) +AC_DEFUN([EIO_CHECK_NOTIFY_WIN32], +[ +_eio_want_notify_win32=$1 +_eio_have_notify_win32="no" + +AC_ARG_ENABLE(notify-win32, + [AC_HELP_STRING([--disable-notify-win32], [disable Windows notification])], + [ + if test "x${enableval}" = "xyes" ; then + _eio_want_notify_win32="yes" + else + _eio_want_notify_win32="no" + fi + ]) + +AC_MSG_CHECKING(whether Windows notification is to be used for filemonitoring) +AC_MSG_RESULT(${_eio_want_notify_win32}) + +if test "x${_eio_want_notify_win32}" = "xyes" ; then + AC_DEFINE([HAVE_NOTIFY_WIN32], [1], [ File monitoring with Windows notification ]) + _eio_have_notify_win32="yes" +fi + +if test "x${_eio_have_notify_win32}" = "xyes" ; then + m4_default([$2], [:]) +else + m4_default([$3], [:]) +fi +]) diff --git a/packaging/eio.spec b/packaging/eio.spec new file mode 100644 index 0000000..8996afd --- /dev/null +++ b/packaging/eio.spec @@ -0,0 +1,61 @@ +%{!?_rel:%{expand:%%global _rel 0.enl%{?dist}}} +%define _missing_doc_files_terminate_build 0 + +Name: eio +Summary: Enlightenment Input/Output Library +Version: 1.7.1+svn.77392+build01r01 +Release: 1 +License: LGPLv2.1 +Group: System Environment/Libraries +URL: http://www.enlightenment.org/ +Source0: %{name}-%{version}.tar.gz +Requires(post): /sbin/ldconfig +Requires(postun): /sbin/ldconfig +BuildRequires: eet-tools +BuildRequires: eina-devel +BuildRequires: eet-devel +BuildRequires: ecore-devel + +%description +Enlightenment input/output library + +%package devel +Summary: EIO headers, static libraries, documentation and test programs +Group: System Environment/Libraries +Requires: %{name} = %{version}-%{release} + +%description devel +Headers, static libraries, test programs and documentation for EIO + +%prep +%setup -q + +%build +export CFLAGS+=" -fPIC -Wall" +export LDFLAGS+=" -Wl,--hash-style=both -Wl,--as-needed" + +%autogen +%configure + +make %{?jobs:-j%jobs} + +%install +rm -rf %{buildroot} +%make_install + +%post -p /sbin/ldconfig + +%postun -p /sbin/ldconfig + +%files +%defattr(-, root, root) +/usr/lib/libeio* +%manifest %{name}.manifest + +%files devel +%defattr(-, root, root) +/usr/include/* +/usr/lib/libeio.so +/usr/lib/pkgconfig/eio.pc + +%changelog diff --git a/src/Makefile.am b/src/Makefile.am index 2433e6c..34a2f0e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,3 +1,4 @@ MAINTAINERCLEANFILES = Makefile.in -SUBDIRS = lib +SUBDIRS = lib \ + examples diff --git a/src/examples/Makefile.am b/src/examples/Makefile.am new file mode 100644 index 0000000..73a8df7 --- /dev/null +++ b/src/examples/Makefile.am @@ -0,0 +1,30 @@ +MAINTAINERCLEANFILES = Makefile.in + +examplesdir = $(datadir)/$(PACKAGE)/examples + +filesdir = $(datadir)/$(PACKAGE)/examples +files_DATA = + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib/ \ +@EIO_CFLAGS@ @EFL_EIO_BUILD@ + +ECOREBASELDADD = \ + $(top_builddir)/src/lib/libeio.la \ + @EIO_LIBS@ + + +LDADD = \ + $(ECOREBASELDADD) + +SRCS = \ + eio_file_ls.c + +examples_PROGRAMS = + +if EFL_BUILD_EXAMPLES +examples_PROGRAMS += \ + eio_file_ls + +endif diff --git a/src/examples/eio_file_ls.c b/src/examples/eio_file_ls.c new file mode 100644 index 0000000..7a9e7f5 --- /dev/null +++ b/src/examples/eio_file_ls.c @@ -0,0 +1,74 @@ +/** + * Compile with gcc -o eio_file_ls eio_file_ls.c `pkg-config --cflags --libs ecore eio` + */ + +#include +#include +#include +#include +#include + +static Eina_Bool +_filter_cb(void *data, Eio_File *handler, const char *file) +{ + char *last_slash = strrchr(file, '/'); + + //Check if it is a hidden file + if (last_slash != NULL && strlen(last_slash) > 1 && last_slash[1] == '.') + return EINA_FALSE; + + return EINA_TRUE; +} + +static void +_main_cb(void *data, Eio_File *handler, const char *file) +{ + int *number_of_listed_files = (int *)data; + + fprintf(stdout, "Processing file:%s\n", file); + + (*number_of_listed_files)++; +} + +static void +_done_cb(void *data, Eio_File *handler) +{ + int *number_of_listed_files = (int *)data; + + fprintf(stdout, "Number of listed files:%d\n" \ + "ls operation is done, quitting.\n", *number_of_listed_files); + + ecore_main_loop_quit(); +} + +static void +_error_cb(void *data, Eio_File *handler, int error) +{ + fprintf(stderr, "Something wrong has happend:%s\n", strerror(error)); + ecore_main_loop_quit(); +} + +int +main(int argc, char **argv) +{ + int number_of_listed_files = 0; + + ecore_init(); + eio_init(); + + if (argc < 2) + { + fprintf(stderr, "You must pass a path to execute the command.\n"); + return -1; + } + + eio_file_ls(argv[1], _filter_cb, _main_cb, _done_cb, _error_cb, + &number_of_listed_files); + + ecore_main_loop_begin(); + + eio_shutdown(); + ecore_shutdown(); + + return 0; +} diff --git a/src/lib/Eio.h b/src/lib/Eio.h index fc2336a..cb791a0 100644 --- a/src/lib/Eio.h +++ b/src/lib/Eio.h @@ -2,6 +2,7 @@ * Copyright (C) 2010 Enlightenment Developers: * Cedric Bail * Vincent "caro" Torri + * Stephen "okra" Houston * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -21,18 +22,19 @@ #ifndef EIO_H__ # define EIO_H__ -#ifdef _MSC_VER -# include -#endif +#include +#include +#include #include +#include #ifdef EAPI # undef EAPI #endif #ifdef _WIN32 -# ifdef EFL_ECORE_BUILD +# ifdef EFL_EIO_BUILD # ifdef DLL_EXPORT # define EAPI __declspec(dllexport) # else @@ -40,7 +42,7 @@ # endif /* ! DLL_EXPORT */ # else # define EAPI __declspec(dllimport) -# endif /* ! EFL_ECORE_BUILD */ +# endif /* ! EFL_EIO_BUILD */ #else # ifdef __GNUC__ # if __GNUC__ >= 4 @@ -53,31 +55,1136 @@ # endif #endif /* ! _WIN32 */ -typedef struct _Eio_List Eio_List; -typedef Eina_Bool (*Eio_Filter_Cb)(const char *file, void *data); -typedef void (*Eio_Main_Cb)(const char *file, void *data); +#ifdef __cplusplus +extern "C" { +#endif + +#define EIO_VERSION_MAJOR 1 +#define EIO_VERSION_MINOR 8 + + /** + * @typedef Eio_Version + * Represents the current version of EIO + */ + typedef struct _Eio_Version + { + int major; /**< Major version number */ + int minor; /**< Minor version number */ + int micro; /**< Micro version number */ + int revision; /**< Revision number */ + } Eio_Version; + + EAPI extern Eio_Version *eio_version; + +/** + * @defgroup Eio_Group Eio Reference API + * + * @brief This is the core asynchronous input/output operation + * + * All the functions in this group perform input/output operations + * in a separate thread using the infrastructure provided by + * Ecore_Thread and Eina, this means that all functions here are non-blocking. + * + * The functions displayed here are used to make basic file operations, like + * listing the content of a directory, creating a new directory, etc. + * + * @{ + */ + +/** + * @enum _Eio_File_Op + * + * @brief Input/Output operations on files. + * + * This enum represents the operations that can be done. + */ +enum _Eio_File_Op +{ + EIO_FILE_COPY, /**< I/O operation is about a specific file copy */ + EIO_FILE_MOVE, /**< I/O operation is about a specific file move */ + EIO_DIR_COPY, /**< I/O operation is about a specific directory copy */ + EIO_DIR_MOVE, /**< I/O operation is about a specific directory move */ + /** I/O operation is about destroying a path: + * source will point to base path to be destroyed, + * and dest will point to to path destroyed by this I/O + */ + EIO_UNLINK, + EIO_FILE_GETPWNAM, /**< I/O operation is trying to get uid from user name */ + EIO_FILE_GETGRNAM /**< I/O operation is trying to get gid from user name */ +}; + +/** + * @typedef Eio_File_Op + * Input/Output operations on files. + */ +typedef enum _Eio_File_Op Eio_File_Op; + +/** + * @typedef Eio_File + * Generic asynchronous I/O reference. + */ +typedef struct _Eio_File Eio_File; + +/** + * @typedef Eio_Progress + * Progress information on a specific operation. + */ +typedef struct _Eio_Progress Eio_Progress; + +typedef Eina_Bool (*Eio_Filter_Cb)(void *data, Eio_File *handler, const char *file); +typedef void (*Eio_Main_Cb)(void *data, Eio_File *handler, const char *file); + +typedef Eina_Bool (*Eio_Filter_Direct_Cb)(void *data, Eio_File *handler, const Eina_File_Direct_Info *info); +typedef Eina_Bool (*Eio_Filter_Dir_Cb)(void *data, Eio_File *handler, Eina_File_Direct_Info *info); +typedef void (*Eio_Main_Direct_Cb)(void *data, Eio_File *handler, const Eina_File_Direct_Info *info); + +typedef void (*Eio_Stat_Cb)(void *data, Eio_File *handler, const Eina_Stat *stat); +typedef void (*Eio_Progress_Cb)(void *data, Eio_File *handler, const Eio_Progress *info); + +typedef void (*Eio_Eet_Open_Cb)(void *data, Eio_File *handler, Eet_File *file); +typedef void (*Eio_Open_Cb)(void *data, Eio_File *handler, Eina_File *file); +typedef Eina_Bool (*Eio_Filter_Map_Cb)(void *data, Eio_File *handler, void *map, size_t length); +typedef void (*Eio_Map_Cb)(void *data, Eio_File *handler, void *map, size_t length); + +typedef void (*Eio_Done_Data_Cb)(void *data, Eio_File *handler, const char *read_data, unsigned int size); +typedef void (*Eio_Done_String_Cb)(void *data, Eio_File *handler, const char *xattr_string); +typedef void (*Eio_Done_Double_Cb)(void *data, Eio_File *handler, double xattr_double); +typedef void (*Eio_Done_Int_Cb)(void *data, Eio_File *handler, int i); + +typedef void (*Eio_Done_ERead_Cb)(void *data, Eio_File *handler, void *decoded); +typedef void (*Eio_Done_Read_Cb)(void *data, Eio_File *handler, void *read_data, unsigned int size); +typedef void (*Eio_Done_Cb)(void *data, Eio_File *handler); +typedef void (*Eio_Error_Cb)(void *data, Eio_File *handler, int error); +typedef void (*Eio_Eet_Error_Cb)(void *data, Eio_File *handler, Eet_Error err); + +/** + * @struct _Eio_Progress + * @brief Represents the current progress of the operation. + */ +struct _Eio_Progress +{ + Eio_File_Op op; /**< I/O type */ + + long long current; /**< Current step in the I/O operation */ + long long max; /**< Number of total steps to complete this I/O */ + float percent; /**< Percent done for the I/O operation */ + + const char *source; /**< source of the I/O operation */ + const char *dest; /**< target of the I/O operation */ +}; + +/** + * @brief List contents of a directory without locking your app. + * @param dir The directory to list. + * @param filter_cb Callback used to decide if the file will be passed to main_cb + * @param main_cb Callback called for each listed file if it was not filtered. + * @param done_cb Callback called when the ls operation is done. + * @param error_cb Callback called when either the directory could not be opened or the operation has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * This function is responsible for listing the content of a directory without blocking your application. + * It's equivalent to the "ls" shell command. Every file will be passed to the + * filter_cb, so it's your job to decide if you want to pass the file to the + * main_cb or not. Return EINA_TRUE to pass it to the main_cb or EINA_FALSE to + * ignore it. + */ +EAPI Eio_File *eio_file_ls(const char *dir, + Eio_Filter_Cb filter_cb, + Eio_Main_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief List contents of a directory without locking your app. + * @param dir The directory to list. + * @param filter_cb Callback used to decide if the file will be passed to main_cb + * @param main_cb Callback called from the main loop for each accepted file (not filtered). + * @param done_cb Callback called from the main loop after the contents of the directory has been listed. + * @param error_cb Callback called from the main loop when either the directory could not be opened or the operation has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_direct_ls runs eina_file_direct_ls in a separate thread using + * ecore_thread_feedback_run. This prevents any blocking in your apps. + * Every file will be passed to the filter_cb, so it's your job to decide if you + * want to pass the file to the main_cb or not. Return EINA_TRUE to pass it to + * the main_cb or EINA_FALSE to ignore it. + */ +EAPI Eio_File *eio_file_direct_ls(const char *dir, + Eio_Filter_Direct_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief List content of a directory without locking your app. + * @param dir The directory to list. + * @param filter_cb Callback used to decide if the file will be passed to main_cb + * @param main_cb Callback called from the main loop for each accepted file (not filtered). + * @param done_cb Callback called from the main loop after the contents of the directory has been listed. + * @param error_cb Callback called from the main loop when either the directory could not be opened or the operation has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * Every file will be passed to the filter_cb, so it's your job to decide if you + * want to pass the file to the main_cb or not. Return EINA_TRUE to pass it to + * the main_cb or EINA_FALSE to ignore it. + * + */ +EAPI Eio_File *eio_file_stat_ls(const char *dir, + Eio_Filter_Direct_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief List the content of a directory and all it's sub-content asynchronously + * @param dir The directory to list. + * @param filter_cb Callback used to decide if the file will be passed to main_cb + * @param main_cb Callback called from the main loop for each accepted file (not filtered). + * @param done_cb Callback called from the main loop after the contents of the directory has been listed. + * @param error_cb Callback called from the main loop when either the directory could not be opened or the operation has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_dir_stat_ls() runs eina_file_stat_ls() recursively in a separate thread using + * ecore_thread_feedback_run. This prevents any blocking in your apps. + * Every file will be passed to the + * filter_cb, so it's your job to decide if you want to pass the file to the + * main_cb or not. Return EINA_TRUE to pass it to the main_cb or EINA_FALSE to + * ignore it. + */ +EAPI Eio_File *eio_dir_stat_ls(const char *dir, + Eio_Filter_Direct_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief List the content of a directory and all it's sub-content asynchronously + * @param dir The directory to list. + * @param filter_cb Callback used to decide if the file will be passed to main_cb + * @param main_cb Callback called from the main loop for each accepted file (not filtered). + * @param done_cb Callback called from the main loop after the contents of the directory has been listed. + * @param error_cb Callback called from the main loop when either the directory could not be opened or the operation has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_dir_direct_ls() runs eina_file_direct_ls() recursively in a separate thread using + * ecore_thread_feedback_run. This prevents any blocking in your apps. + * Every file will be passed to the filter_cb, so it's your job to decide if you + * want to pass the file to the main_cb or not. Return EINA_TRUE to pass it to + * the main_cb or EINA_FALSE to ignore it. + */ +EAPI Eio_File *eio_dir_direct_ls(const char *dir, + Eio_Filter_Dir_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Stat a file/directory. + * @param path The path to stat. + * @param done_cb Callback called from the main loop when stat was successfully called. + * @param error_cb Callback called from the main loop when stat failed or has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_direct_stat calls stat in another thread. This prevents any blocking in your apps. + */ +EAPI Eio_File *eio_file_direct_stat(const char *path, + Eio_Stat_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Change right of a path. + * @param path The directory path to change access right. + * @param mode The permission to set, follow (mode & ~umask & 0777). + * @param done_cb Callback called when the operation is completed. + * @param error_cb Callback called from if something goes wrong. + * @param data Unmodified user data passed to callbacks. + * @return A reference to the I/O operation. + * + * Set a new permission of a path changing it to the mode passed as argument. + * It's equivalent to the chmod command. + */ +EAPI Eio_File *eio_file_chmod(const char *path, + mode_t mode, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Change owner of a path. + * @param path The directory path to change owner. + * @param user The new user to set (can be NULL). + * @param group The new group to set (can be NULL). + * @param done_cb Callback called when the operation is completed. + * @param error_cb Callback called from if something goes wrong. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * This function will change the owner of a path, setting it to the user and + * group passed as argument. It's equivalent to the chown shell command. + */ +EAPI Eio_File *eio_file_chown(const char *path, + const char *user, + const char *group, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Unlink a file/directory. + * @param path The path to unlink. + * @param done_cb Callback called when the operation is completed. + * @param error_cb Callback called from if something goes wrong. + * @param data Unmodified user data passed to callbacks. + * @return A reference to the I/O operation. + * + * This function will erase a file. + */ +EAPI Eio_File *eio_file_unlink(const char *path, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Create a new directory. + * @param path The directory path to create. + * @param mode The permission to set, follow (mode & ~umask & 0777). + * @param done_cb Callback called when the operation is completed. + * @param error_cb Callback called from if something goes wrong. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * Creates a new directory using the mode provided. + */ +EAPI Eio_File *eio_file_mkdir(const char *path, + mode_t mode, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Move a file asynchronously + * @param source Should be the name of the file to move the data from. + * @param dest Should be the name of the file to move the data to. + * @param progress_cb Callback called to know the progress of the move. + * @param done_cb Callback called when the move is done. + * @param error_cb Callback called when something goes wrong. + * @param data Unmodified user data passed to callbacks + * + * This function will copy a file from source to dest. It will try to use splice + * if possible, if not it will fallback to mmap/write. It will try to preserve + * access right, but not user/group identification. + */ +EAPI Eio_File *eio_file_move(const char *source, + const char *dest, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Copy a file asynchronously + * @param source Should be the name of the file to copy the data from. + * @param dest Should be the name of the file to copy the data to. + * @param progress_cb Callback called to know the progress of the copy. + * @param done_cb Callback called when the copy is done. + * @param error_cb Callback called when something goes wrong. + * @param data Unmodified user data passed to callbacks + * + * This function will copy a file from source to dest. It will try to use splice + * if possible, if not it will fallback to mmap/write. It will try to preserve + * access right, but not user/group identification. + */ +EAPI Eio_File *eio_file_copy(const char *source, + const char *dest, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Move a directory and it's content asynchronously + * @param source Should be the name of the directory to copy the data from. + * @param dest Should be the name of the directory to copy the data to. + * @param filter_cb Possible to deny the move of some files/directories. + * @param progress_cb Callback called to know the progress of the copy. + * @param done_cb Callback called when the copy is done. + * @param error_cb Callback called when something goes wrong. + * @param data Unmodified user data passed to callbacks + * + * This function will move a directory and all it's content from source to dest. + * It will try first to rename the directory, if not it will try to use splice + * if possible, if not it will fallback to mmap/write. + * It will try to preserve access right, but not user/group identity. + * Every file will be passed to the filter_cb, so it's your job to decide if you + * want to pass the file to the main_cb or not. Return EINA_TRUE to pass it to + * the main_cb or EINA_FALSE to ignore it. + * + * @note if a rename occur, the filter callback will not be called. + */ +EAPI Eio_File *eio_dir_move(const char *source, + const char *dest, + Eio_Filter_Direct_Cb filter_cb, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Copy a directory and it's content asynchronously + * @param source Should be the name of the directory to copy the data from. + * @param dest Should be the name of the directory to copy the data to. + * @param filter_cb Possible to deny the move of some files/directories. + * @param progress_cb Callback called to know the progress of the copy. + * @param done_cb Callback called when the copy is done. + * @param error_cb Callback called when something goes wrong. + * @param data Unmodified user data passed to callbacks + * + * This function will copy a directory and all it's content from source to dest. + * It will try to use splice if possible, if not it will fallback to mmap/write. + * It will try to preserve access right, but not user/group identity. + * Every file will be passed to the filter_cb, so it's your job to decide if you + * want to pass the file to the main_cb or not. Return EINA_TRUE to pass it to + * the main_cb or EINA_FALSE to ignore it. + */ +EAPI Eio_File *eio_dir_copy(const char *source, + const char *dest, + Eio_Filter_Direct_Cb filter_cb, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Remove a directory and it's content asynchronously + * @param path Should be the name of the directory to destroy. + * @param filter_cb Possible to deny the move of some files/directories. + * @param progress_cb Callback called to know the progress of the copy. + * @param done_cb Callback called when the copy is done. + * @param error_cb Callback called when something goes wrong. + * @param data Unmodified user data passed to callbacks + * + * This function will remove a directory and all it's content. + * Every file will be passed to the filter_cb, so it's your job to decide if you + * want to pass the file to the main_cb or not. Return EINA_TRUE to pass it to + * the main_cb or EINA_FALSE to ignore it. + */ +EAPI Eio_File *eio_dir_unlink(const char *path, + Eio_Filter_Direct_Cb filter_cb, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @} + */ + + +/** + * @defgroup Eio_Xattr Eio manipulation of eXtended attribute. + * + * @brief A set of function to manipulate data associated with a specific file + * + * The functions provided by this API are responsible to manage Extended + * attribute files. Like file authors, character encoding, checksum, etc. + * @{ + */ -typedef Eina_Bool (*Eio_Filter_Direct_Cb)(const Eina_File_Direct_Info *info, void *data); -typedef void (*Eio_Main_Direct_Cb)(const Eina_File_Direct_Info *info, void *data); +/** + * @brief Assynchronously list all eXtended attribute + * @param path The path to get the eXtended attribute from. + * @param filter_cb Callback called in the thread to validate the eXtended attribute. + * @param main_cb Callback called in the main loop for each accepted eXtended attribute. + * @param done_cb Callback called in the main loop when the all the eXtended attribute have been listed. + * @param error_cb Callback called in the main loop when something goes wrong during the listing of the eXtended attribute. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + */ +EAPI Eio_File *eio_file_xattr(const char *path, + Eio_Filter_Cb filter_cb, + Eio_Main_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Define an extented attribute on a file/directory. + * @param path The path to set the attribute on. + * @param attribute The name of the attribute to define. + * @param xattr_int The value to link the attribute with. + * @param flags Wether to insert, replace or create the attribute. + * @param done_cb The callback called from the main loop when setxattr succeeded. + * @param error_cb The callback called from the main loop when setxattr failed. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_int_set calls eina_xattr_int_set from another thread. This prevents blocking in your apps. If + * the writing succeeded, the done_cb will be called even if a cancel was requested, but came to late. + */ +EAPI Eio_File *eio_file_xattr_int_set(const char *path, + const char *attribute, + int xattr_int, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); -typedef void (*Eio_Done_Cb)(void *data); +/** + * @brief Define an extented attribute on a file/directory. + * @param path The path to set the attribute on. + * @param attribute The name of the attribute to define. + * @param xattr_double The value to link the attribute with. + * @param flags Wether to insert, replace or create the attribute. + * @param done_cb The callback called from the main loop when setxattr succeeded. + * @param error_cb The callback called from the main loop when setxattr failed. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_double_set calls eina_xattr_double_set from another thread. This prevents blocking in your apps. If + * the writing succeeded, the done_cb will be called even if a cancel was requested, but came to late. + */ +EAPI Eio_File *eio_file_xattr_double_set(const char *path, + const char *attribute, + double xattr_double, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @brief Define a string extented attribute on a file/directory. + * @param path The path to set the attribute on. + * @param attribute The name of the attribute to define. + * @param xattr_string The string to link the attribute with. + * @param flags Wether to insert, replace or create the attribute. + * @param done_cb The callback called from the main loop when setxattr succeeded. + * @param error_cb The callback called from the main loop when setxattr failed. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_string_set calls eina_xattr_string_set from another thread. This prevents blocking in your apps. If + * the writing succeeded, the done_cb will be called even if a cancel was requested, but came to late. + */ +EAPI Eio_File *eio_file_xattr_string_set(const char *path, + const char *attribute, + const char *xattr_string, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @brief Define an extented attribute on a file/directory. + * @param path The path to set the attribute on. + * @param attribute The name of the attribute to define. + * @param xattr_data The data to link the attribute with. + * @param xattr_size The size of the data to set. + * @param flags Wether to insert, replace or create the attribute. + * @param done_cb The callback called from the main loop when setxattr succeeded. + * @param error_cb The callback called from the main loop when setxattr failed. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_set calls setxattr from another thread. This prevents blocking in your apps. If + * the writing succeeded, the done_cb will be called even if a cancel was requested, but came to late. + */ +EAPI Eio_File *eio_file_xattr_set(const char *path, + const char *attribute, + const char *xattr_data, + unsigned int xattr_size, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @brief Retrieve the extended attribute of a file/directory. + * @param path The path to retrieve the extended attribute from. + * @param attribute The name of the attribute to retrieve. + * @param done_cb Callback called from the main loop when getxattr succeeded. + * @param error_cb Callback called from the main loop when getxattr failed or has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_get calls getxattr from another thread. This prevents blocking in your apps. + */ +EAPI Eio_File *eio_file_xattr_get(const char *path, + const char *attribute, + Eio_Done_Data_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @brief Retrieve a extended attribute of a file/directory. + * @param path The path to retrieve the extended attribute from. + * @param attribute The name of the attribute to retrieve. + * @param done_cb Callback called from the main loop when getxattr succeeded. + * @param error_cb Callback called from the main loop when getxattr failed or has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_int_get calls eina_xattr_int_get from another thread. This prevents blocking in your apps. + */ +EAPI Eio_File *eio_file_xattr_int_get(const char *path, + const char *attribute, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @brief Retrieve a extended attribute of a file/directory. + * @param path The path to retrieve the extended attribute from. + * @param attribute The name of the attribute to retrieve. + * @param done_cb Callback called from the main loop when getxattr succeeded. + * @param error_cb Callback called from the main loop when getxattr failed or has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_double_get calls eina_xattr_double_get from another thread. This prevents blocking in your apps. + */ +EAPI Eio_File *eio_file_xattr_double_get(const char *path, + const char *attribute, + Eio_Done_Double_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @brief Retrieve a string extended attribute of a file/directory. + * @param path The path to retrieve the extended attribute from. + * @param attribute The name of the attribute to retrieve. + * @param done_cb Callback called from the main loop when getxattr succeeded. + * @param error_cb Callback called from the main loop when getxattr failed or has been canceled. + * @param data Unmodified user data passed to callbacks + * @return A reference to the I/O operation. + * + * eio_file_xattr_string_get calls eina_xattr_string_get from another thread. This prevents blocking in your apps. + */ +EAPI Eio_File *eio_file_xattr_string_get(const char *path, + const char *attribute, + Eio_Done_String_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @} + */ + +/** + * @defgroup Eio_Helper Eio Reference helper API + * + * @brief This are helper provided around core Eio API. + * + * This set of functions do provide helper to work around data + * provided by Eio without the need to look at system header. + * + * @{ + */ + + +/** + * @brief Initialize eio and all it's required submodule. + * @return the current number of eio users. + */ EAPI int eio_init(void); + +/** + * @brief Shutdown eio and all it's submodule if possible. + * @return the number of pending users of eio. + */ EAPI int eio_shutdown(void); -EAPI Eio_List *eio_file_ls(const char *dir, - Eio_Filter_Cb filter, - Eio_Main_Cb main, - Eio_Done_Cb done, - const void *data); +/** + * @brief Return the container during EIO operation + * @param ls The asynchronous I/O operation to retrieve container from. + * @return NULL if not available, a DIRP if it is. + * + * This is only available and make sense in the thread callback, not in + * the mainloop. + */ +EAPI void *eio_file_container_get(Eio_File *ls); + +/** + * @brief Cancel any Eio_File. + * @param ls The asynchronous I/O operation to cancel. + * @return EINA_FALSE if the destruction is delayed, EINA_TRUE if it's done. + * + * This will cancel any kind of I/O operation and cleanup the mess. This means + * that it could take time to cancel an I/O. + */ +EAPI Eina_Bool eio_file_cancel(Eio_File *ls); + +/** + * @brief Check if an Eio_File operation has been cancelled. + * @param ls The asynchronous I/O operation to check. + * @return EINA_TRUE if it was canceled, EINA_FALSE other wise. + * + * In case of an error it also return EINA_TRUE. + */ +EAPI Eina_Bool eio_file_check(Eio_File *ls); + +/** + * @brief Associate data with the current filtered file. + * @param ls The Eio_File ls request currently calling the filter callback. + * @param key The key to associate data to. + * @param data The data to associate the data to. + * @param free_cb Optionally a function to call to free the associated data, + * @p data is passed as the callback data parameter. If no @free_cb is provided + * the user @p data remains untouched. + * @return EINA_TRUE if insertion was fine. + * + * This function can only be safely called from within the filter callback. + * If you don't need to copy the key around you can use @ref eio_file_associate_direct_add + */ +EAPI Eina_Bool eio_file_associate_add(Eio_File *ls, + const char *key, + const void *data, Eina_Free_Cb free_cb); + +/** + * @brief Associate data with the current filtered file. + * @param ls The Eio_File ls request currently calling the filter callback. + * @param key The key to associate data to (will not be copied, and the pointer will not be used as long as the file is not notified). + * @param data The data to associate the data to. + * @param free_cb The function to call to free the associated data, @p free will be called if not specified. + * @return EINA_TRUE if insertion was fine. + * + * This function can only be safely called from within the filter callback. + * If you need eio to make a proper copy of the @p key to be safe use + * @ref eio_file_associate_add instead. + */ +EAPI Eina_Bool eio_file_associate_direct_add(Eio_File *ls, + const char *key, + const void *data, Eina_Free_Cb free_cb); + +/** + * @brief Get the data associated during the filter callback inside the main loop + * @param ls The Eio_File ls request currently calling the notify callback. + * @param key The key pointing to the data to retrieve. + * @return the data associated with the key or @p NULL if not found. + */ +EAPI void *eio_file_associate_find(Eio_File *ls, const char *key); + +/** + * @brief get access time from a Eina_Stat + * @param stat the structure to get the atime from + * @return the last accessed time + * + * This take care of doing type conversion to match rest of EFL time API. + * @note some filesystem don't update that information. + */ +static inline double eio_file_atime(const Eina_Stat *stat); + +/** + * @brief get modification time from a Eina_Stat + * @param stat the structure to get the mtime from + * @return the last modification time + * + * This take care of doing type conversion to match rest of EFL time API. + */ +static inline double eio_file_mtime(const Eina_Stat *stat); + +/** + * @brief get the size of the file described in Eina_Stat + * @param stat the structure to get the size from + * @return the size of the file + */ +static inline long long eio_file_size(const Eina_Stat *stat); + +/** + * @brief tell if the stated path was a directory or not. + * @param stat the structure to get the size from + * @return EINA_TRUE, if it was. + */ +static inline Eina_Bool eio_file_is_dir(const Eina_Stat *stat); + +/** + * @brief tell if the stated path was a link or not. + * @param stat the structure to get the size from + * @return EINA_TRUE, if it was. + */ +static inline Eina_Bool eio_file_is_lnk(const Eina_Stat *stat); + +/** + * @} + */ -EAPI Eio_List *eio_file_direct_ls(const char *dir, - Eio_Filter_Direct_Cb filter, - Eio_Main_Direct_Cb main, - Eio_Done_Cb done, - const void *data); +/** + * + */ + +/** + * @defgroup Eio_Map Manipulate an Eina_File asynchronously + * + * @brief This function help manipulating file asynchronously. + * + * This set of function work on top of Eina_File and Ecore_Thread to + * do basic operations in a file, like openning, closing and mapping a file to + * memory. + * @{ + */ + +/** + * @brief Assynchronously open a file. + * @param name The file to open. + * @param shared If it's a shared memory file. + * @param open_cb Callback called in the main loop when the file has been successfully opened. + * @param error_cb Callback called in the main loop when the file couldn't be opened. + * @param data Unmodified user data passed to callbacks + * @return Pointer to the file if successfull or NULL otherwise. + * + */ +EAPI Eio_File *eio_file_open(const char *name, Eina_Bool shared, + Eio_Open_Cb open_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Assynchronously close a file. + * @param f The file to close. + * @param done_cb Callback called in the main loop when the file has been successfully closed. + * @param error_cb Callback called in the main loop when the file couldn't be closed. + * @param data Unmodified user data passed to callbacks + * @return Pointer to the file if successfull or NULL otherwise. + */ +EAPI Eio_File *eio_file_close(Eina_File *f, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Assynchronously map a file in memory. + * @param f The file to map. + * @param rule The rule to apply to the map. + * @param filter_cb Callback called in the thread to validate the content of the map. + * @param map_cb Callback called in the main loop when the file has been successfully mapped. + * @param error_cb Callback called in the main loop when the file can't be mapped. + * @param data Unmodified user data passed to callbacks + * @return Pointer to the file if successfull or NULL otherwise. + * + * The container of the Eio_File is the Eina_File. + */ +EAPI Eio_File *eio_file_map_all(Eina_File *f, + Eina_File_Populate rule, + Eio_Filter_Map_Cb filter_cb, + Eio_Map_Cb map_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Assynchronously map a part of a file in memory. + * @param f The file to map. + * @param rule The rule to apply to the map. + * @param offset The offset inside the file + * @param length The length of the memory to map + * @param filter_cb Callback called in the thread to validate the content of the map. + * @param map_cb Callback called in the main loop when the file has been successfully mapped. + * @param error_cb Callback called in the main loop when the file can't be mapped. + * @param data Unmodified user data passed to callbacks + * @return Pointer to the file if successfull or NULL otherwise. + * + * The container of the Eio_File is the Eina_File. + */ +EAPI Eio_File *eio_file_map_new(Eina_File *f, + Eina_File_Populate rule, + unsigned long int offset, + unsigned long int length, + Eio_Filter_Map_Cb filter_cb, + Eio_Map_Cb map_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @} + */ + +/** + * @defgroup Eio_Eet Eio asynchronous API for Eet file. + * + * @brief This set of functions help in the asynchronous use of Eet + * + * @{ + */ + +/** + * @brief Open an eet file on disk, and returns a handle to it asynchronously. + * @param filename The file path to the eet file. eg: @c "/tmp/file.eet". + * @param mode The mode for opening. Either EET_FILE_MODE_READ, + * EET_FILE_MODE_WRITE or EET_FILE_MODE_READ_WRITE. + * @param eet_cb The callback to call when the file has been successfully opened. + * @param error_cb Callback called in the main loop when the file can't be opened. + * @param data Unmodified user data passed to callbacks + * @return NULL in case of a failure. + * + * This function calls eet_open() from another thread using Ecore_Thread. + */ +EAPI Eio_File *eio_eet_open(const char *filename, + Eet_File_Mode mode, + Eio_Eet_Open_Cb eet_cb, + Eio_Error_Cb error_cb, + const void *data); +/** + * @brief Close an eet file handle and flush pending writes asynchronously. + * @param ef A valid eet file handle. + * @param done_cb Callback called from the main loop when the file has been closed. + * @param error_cb Callback called in the main loop when the file can't be closed. + * @param data Unmodified user data passed to callbacks + * @return NULL in case of a failure. + * + * This function will call eet_close() from another thread by + * using Ecore_Thread. You should assume that the Eet_File is dead after this + * function is called. + */ +EAPI Eio_File *eio_eet_close(Eet_File *ef, + Eio_Done_Cb done_cb, + Eio_Eet_Error_Cb error_cb, + const void *data); + +/** + * @brief Sync content of an eet file handle, flushing pending writes asynchronously. + * @param ef A valid eet file handle. + * @param done_cb Callback called from the main loop when the file has been synced. + * @param error_cb Callback called in the main loop when the file can't be synced. + * @param data Unmodified user data passed to callbacks + * @return NULL in case of a failure. + * + * This function will call eet_flush() from another thread. As long as the done_cb or + * error_cb haven't be called, you must keep @p ef open. + */ +EAPI Eio_File *eio_eet_sync(Eet_File *ef, + Eio_Done_Cb done_cb, + Eio_Eet_Error_Cb error_cb, + const void *data); + +/** + * @brief Write a data structure from memory and store in an eet file + * using a cipher asynchronously. + * @param ef The eet file handle to write to. + * @param edd The data descriptor to use when encoding. + * @param name The key to store the data under in the eet file. + * @param cipher_key The key to use as cipher. + * @param write_data A pointer to the data structure to save and encode. + * @param compress Compression flags for storage. + * @param done_cb Callback called from the main loop when the data has been put in the Eet_File. + * @param error_cb Callback called in the main loop when the file can't be written. + * @param user_data Private data given to each callback. + * @return NULL in case of a failure. + */ +EAPI Eio_File *eio_eet_data_write_cipher(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name, + const char *cipher_key, + void *write_data, + int compress, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *user_data); + +/** + * @brief Read a data structure from an eet file and decodes it using a cipher asynchronously. + * @param ef The eet file handle to read from. + * @param edd The data descriptor handle to use when decoding. + * @param name The key the data is stored under in the eet file. + * @param cipher_key The key to use as cipher. + * @param done_cb Callback called from the main loop when the data has been read and decoded. + * @param error_cb Callback called in the main loop when the data can't be read. + * @param data Unmodified user data passed to callbacks + * @return NULL in case of a failure. + */ +EAPI Eio_File *eio_eet_data_read_cipher(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name, + const char *cipher_key, + Eio_Done_ERead_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Write image data to the named key in an eet file asynchronously. + * @param ef A valid eet file handle opened for writing. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param cipher_key The key to use as cipher. + * @param write_data A pointer to the image pixel data. + * @param w The width of the image in pixels. + * @param h The height of the image in pixels. + * @param alpha The alpha channel flag. + * @param compress The compression amount. + * @param quality The quality encoding amount. + * @param lossy The lossiness flag. + * @param done_cb Callback called from the main loop when the data has been put in the Eet_File. + * @param error_cb Callback called in the main loop when the file can't be written. + * @param user_data Private data given to each callback. + * @return NULL in case of a failure. + */ +EAPI Eio_File *eio_eet_data_image_write_cipher(Eet_File *ef, + const char *name, + const char *cipher_key, + void *write_data, + unsigned int w, + unsigned int h, + int alpha, + int compress, + int quality, + int lossy, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *user_data); + +/** + * @brief Read a specified entry from an eet file and return data + * @param ef A valid eet file handle opened for reading. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param done_cb Callback called from the main loop when the data has been read. + * @param error_cb Callback called in the main loop when the data can't be read. + * @param data Unmodified user data passed to callbacks + * @return NULL in case of a failure. + */ +EAPI Eio_File *eio_eet_read_direct(Eet_File *ef, + const char *name, + Eio_Done_Data_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Read a specified entry from an eet file and return data + * @param ef A valid eet file handle opened for reading. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param cipher_key The key to use as cipher. + * @param done_cb Callback called from the main loop when the data has been read. + * @param error_cb Callback called in the main loop when the data can't be read. + * @param data Unmodified user data passed to callbacks + * @return NULL in case of a failure. + */ +EAPI Eio_File *eio_eet_read_cipher(Eet_File *ef, + const char *name, + const char *cipher_key, + Eio_Done_Read_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data); + +/** + * @brief Write a specified entry to an eet file handle using a cipher. + * @param ef A valid eet file handle opened for writing. + * @param name Name of the entry. eg: "/base/file_i_want". + * @param write_data Pointer to the data to be stored. + * @param size Length in bytes in the data to be stored. + * @param compress Compression flags (1 == compress, 0 = don't compress). + * @param cipher_key The key to use as cipher. + * @param done_cb Callback called from the main loop when the data has been put in the Eet_File. + * @param error_cb Callback called in the main loop when the file can't be written. + * @param user_data Private data given to each callback. + * @return NULL in case of a failure. + */ +EAPI Eio_File *eio_eet_write_cipher(Eet_File *ef, + const char *name, + void *write_data, + int size, + int compress, + const char *cipher_key, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *user_data); + +/** + * @} + */ + +/** + * @defgroup Eio_Monitor Eio file and directory monitoring API + * + * @brief These function monitor changes in directories and files + * + * These functions use the best available method to monitor changes on a specified directory + * or file. They send ecore events when changes occur, and they maintain internal refcounts to + * reduce resource consumption on duplicate monitor targets. + * + * @{ + */ + +EAPI extern int EIO_MONITOR_FILE_CREATED; /**< A new file was created in a watched directory */ +EAPI extern int EIO_MONITOR_FILE_DELETED; /**< A watched file was deleted, or a file in a watched directory was deleted */ +EAPI extern int EIO_MONITOR_FILE_MODIFIED; /**< A file was modified in a watched directory */ +EAPI extern int EIO_MONITOR_FILE_CLOSED; /**< A file was closed in a watched directory. This event is never sent on Windows */ +EAPI extern int EIO_MONITOR_DIRECTORY_CREATED; /**< A new directory was created in a watched directory */ +EAPI extern int EIO_MONITOR_DIRECTORY_DELETED; /**< A directory has been deleted: this can be either a watched directory or one of its subdirectories */ +EAPI extern int EIO_MONITOR_DIRECTORY_MODIFIED; /**< A directory has been modified in a watched directory */ +EAPI extern int EIO_MONITOR_DIRECTORY_CLOSED; /**< A directory has been closed in a watched directory. This event is never sent on Windows */ +EAPI extern int EIO_MONITOR_SELF_RENAME; /**< The monitored path has been renamed, an error could happen just after if the renamed path doesn't exist */ +EAPI extern int EIO_MONITOR_SELF_DELETED; /**< The monitored path has been removed */ +EAPI extern int EIO_MONITOR_ERROR; /**< During operation the monitor failed and will no longer work. eio_monitor_del must be called on it. */ + +typedef struct _Eio_Monitor Eio_Monitor; + +typedef struct _Eio_Monitor_Error Eio_Monitor_Error; +typedef struct _Eio_Monitor_Event Eio_Monitor_Event; + +struct _Eio_Monitor_Error +{ + Eio_Monitor *monitor; + int error; +}; + +struct _Eio_Monitor_Event +{ + Eio_Monitor *monitor; + const char *filename; +}; + +/** + * @brief Adds a file/directory to monitor (inotify mechanism) + * @param path file/directory to monitor + * @return NULL in case of a failure or a pointer to the monitor in case of + * success. + * + * This function will add the given path to its internal + * list of files to monitor. It utilizes the inotify mechanism + * introduced in kernel 2.6.13 for passive monitoring. + */ +EAPI Eio_Monitor *eio_monitor_add(const char *path); + +/** + * @brief Adds a file/directory to monitor + * @param path file/directory to monitor + * @return NULL in case of a failure or a pointer to the monitor in case of + * success. + * @warning Do NOT pass non-stringshared strings to this function! + * If you don't know what this means, use eio_monitor_add(). + * + * This fuction is just like eio_monitor_add(), however the string passed by + * argument must be created using eina_stringshare_add(). + */ +EAPI Eio_Monitor *eio_monitor_stringshared_add(const char *path); + +/** + * @brief Deletes a path from the “watched” list + * @param monitor The Eio_Monitor you want to stop watching. + * It can only be an Eio_Monitor returned to you from calling + * eio_monitor_add() or eio_monitor_stringshared_add() + */ +EAPI void eio_monitor_del(Eio_Monitor *monitor); + +/** + * @brief returns the path being watched by the given + * Eio_Monitor. + * @param monitor Eio_Monitor to return the path of + * @return The stringshared path belonging to @p monitor + */ +EAPI const char *eio_monitor_path_get(Eio_Monitor *monitor); + +/** + * @} + */ + +#include "eio_inline_helper.x" + +#ifdef __cplusplus +} +#endif -EAPI Eina_Bool eio_file_cancel(Eio_List *list); #endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index d2bdf3b..73d3c23 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -1,16 +1,34 @@ MAINTAINERCLEANFILES = Makefile.in -AM_CPPFLAGS = @EIO_CFLAGS@ -AM_CFLAGS = @EIO_CFLAGS@ +AM_CPPFLAGS = @EIO_CFLAGS@ \ +@EFL_PTHREAD_CFLAGS@ \ +@EFL_EIO_BUILD@ lib_LTLIBRARIES = libeio.la -includes_HEADERS = Eio.h +includes_HEADERS = Eio.h eio_inline_helper.x includesdir = $(includedir)/eio-@VMAJ@ libeio_la_SOURCES = \ -eio_file.c +eio_dir.c \ +eio_eet.c \ +eio_file.c \ +eio_main.c \ +eio_map.c \ +eio_monitor.c \ +eio_monitor_poll.c \ +eio_single.c \ +eio_xattr.c -libeio_la_LIBADD = @EIO_LIBS@ +if EIO_HAVE_INOTIFY +libeio_la_SOURCES += eio_monitor_inotify.c +else +if EIO_HAVE_WINCHANGE +libeio_la_SOURCES += eio_monitor_win32.c +endif +endif + +libeio_la_LIBADD = @EIO_LIBS@ @EFL_PTHREAD_LIBS@ libeio_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ +EXTRA_DIST = eio_private.h diff --git a/src/lib/eio_dir.c b/src/lib/eio_dir.c new file mode 100644 index 0000000..7bed4fb --- /dev/null +++ b/src/lib/eio_dir.c @@ -0,0 +1,1001 @@ +/* EIO - EFL data type library + * Copyright (C) 2010 Enlightenment Developers: + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +static int +eio_strcmp(const void *a, const void *b) +{ + return strcmp(a, b); +} +static Eina_Bool +_eio_dir_recursive_progress(Eio_Dir_Copy *copy, Eio_File *handler, const Eina_File_Direct_Info *info) +{ + if (copy->filter_cb && !copy->filter_cb(©->progress.common.data, handler, info)) + return EINA_FALSE; + + switch (info->type) + { + case EINA_FILE_UNKNOWN: + eio_file_thread_error(©->progress.common, handler->thread); + return EINA_FALSE; + case EINA_FILE_LNK: + copy->links = eina_list_append(copy->links, eina_stringshare_add(info->path)); + break; + case EINA_FILE_DIR: + copy->dirs = eina_list_append(copy->dirs, eina_stringshare_add(info->path)); + break; + default: + copy->files = eina_list_append(copy->files, eina_stringshare_add(info->path)); + break; + } + + return EINA_TRUE; +} + +static Eina_Bool +_eio_file_recursiv_ls(Ecore_Thread *thread, + Eio_File *common, + Eio_Filter_Direct_Cb filter_cb, + Eina_Iterator *(*Eina_File_Ls)(const char *target), + void *data, + const char *target) +{ + Eina_File_Direct_Info *info; + Eina_Iterator *it = NULL; + Eina_List *dirs = NULL; + const char *dir; + + it = Eina_File_Ls(target); + if (!it) + { + eio_file_thread_error(common, thread); + return EINA_FALSE; + } + + eio_file_container_set(common, eina_iterator_container_get(it)); + + EINA_ITERATOR_FOREACH(it, info) + { + Eina_Bool filter = EINA_TRUE; + _eio_stat_t buffer; + + switch (info->type) + { + case EINA_FILE_DIR: + if (_eio_lstat(info->path, &buffer) != 0) + continue; + + if (S_ISLNK(buffer.st_mode)) + info->type = EINA_FILE_LNK; + default: + break; + } + + filter = filter_cb(data, common, info); + if (filter && info->type == EINA_FILE_DIR) + dirs = eina_list_append(dirs, eina_stringshare_add(info->path)); + + if (ecore_thread_check(thread)) + goto on_error; + } + + eio_file_container_set(common, NULL); + + eina_iterator_free(it); + it = NULL; + + EINA_LIST_FREE(dirs, dir) + { + Eina_Bool err; + + err = !_eio_file_recursiv_ls(thread, common, filter_cb, Eina_File_Ls, data, dir); + + eina_stringshare_del(dir); + if (err) goto on_error; + } + + return EINA_TRUE; + + on_error: + if (it) eina_iterator_free(it); + + EINA_LIST_FREE(dirs, dir) + eina_stringshare_del(dir); + + return EINA_FALSE; +} + + +static Eina_Bool +_eio_dir_recursiv_ls(Ecore_Thread *thread, Eio_Dir_Copy *copy, const char *target) +{ + if (!_eio_file_recursiv_ls(thread, ©->progress.common, + (Eio_Filter_Direct_Cb) _eio_dir_recursive_progress, + eina_file_stat_ls, + copy, target)) + return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +_eio_dir_init(Ecore_Thread *thread, + long long *step, long long *count, + int *length_source, int *length_dest, + Eio_Dir_Copy *order, + Eio_File_Progress *progress) +{ + struct stat buffer; + + /* notify main thread of the amount of work todo */ + *step = 0; + *count = eina_list_count(order->files) + + eina_list_count(order->dirs) * 2 + + eina_list_count(order->links); + eio_progress_send(thread, &order->progress, *step, *count); + + /* sort the content, so we create the directory in the right order */ + order->dirs = eina_list_sort(order->dirs, -1, eio_strcmp); + order->files = eina_list_sort(order->files, -1, eio_strcmp); + order->links = eina_list_sort(order->links, -1, eio_strcmp); + + /* prepare stuff */ + *length_source = eina_stringshare_strlen(order->progress.source); + *length_dest = eina_stringshare_strlen(order->progress.dest); + + memcpy(progress, &order->progress, sizeof (Eio_File_Progress)); + progress->source = NULL; + progress->dest = NULL; + + /* create destination dir if not available */ + if (stat(order->progress.dest, &buffer) != 0) + { + if (stat(order->progress.source, &buffer) != 0) + { + eio_file_thread_error(&order->progress.common, thread); + return EINA_FALSE; + } + + if (mkdir(order->progress.dest, buffer.st_mode) != 0) + { + eio_file_thread_error(&order->progress.common, thread); + return EINA_FALSE; + } + } + + return EINA_TRUE; +} + +static void +_eio_dir_target(Eio_Dir_Copy *order, char *target, const char *dir, int length_source, int length_dest) +{ + int length; + + length = eina_stringshare_strlen(dir); + + memcpy(target, order->progress.dest, length_dest); + target[length_dest] = '/'; + memcpy(target + length_dest + 1, dir + length_source, length - length_source + 1); +} + +static Eina_Bool +_eio_dir_mkdir(Ecore_Thread *thread, Eio_Dir_Copy *order, + long long *step, long long count, + int length_source, int length_dest) +{ + const char *dir; + Eina_List *l; + char target[PATH_MAX]; + + /* create all directory */ + EINA_LIST_FOREACH(order->dirs, l, dir) + { + /* build target dir path */ + _eio_dir_target(order, target, dir, length_source, length_dest); + + /* create the directory (we will apply the mode later) */ + if (mkdir(target, 0777) != 0) + { + eio_file_thread_error(&order->progress.common, thread); + return EINA_FALSE; + } + + /* inform main thread */ + (*step)++; + eio_progress_send(thread, &order->progress, *step, count); + + /* check for cancel request */ + if (ecore_thread_check(thread)) + return EINA_FALSE; + } + + return EINA_TRUE; +} + +static Eina_Bool +_eio_dir_link(Ecore_Thread *thread, Eio_Dir_Copy *order, + long long *step, long long count, + int length_source, int length_dest) +{ + const char *ln; + Eina_List *l; + char oldpath[PATH_MAX]; + char target[PATH_MAX]; + char buffer[PATH_MAX]; + char *newpath; + + /* Build once the base of the link target */ + memcpy(buffer, order->progress.dest, length_dest); + buffer[length_dest] = '/'; + + /* recreate all links */ + EINA_LIST_FOREACH(order->links, l, ln) + { + ssize_t length; + + /* build oldpath link */ + _eio_dir_target(order, oldpath, ln, length_source, length_dest); + + /* read link target */ + length = readlink(ln, target, PATH_MAX); + if (length < 0) + goto on_error; + + if (strncmp(target, order->progress.source, length_source) == 0) + { + /* The link is inside the zone to copy, so rename it */ + memcpy(buffer + length_dest + 1, target + length_source, length - length_source + 1); + newpath = target; + } + else + { + /* The link is outside the zone to copy */ + newpath = target; + } + + /* create the link */ + if (symlink(newpath, oldpath) != 0) + goto on_error; + + /* inform main thread */ + (*step)++; + eio_progress_send(thread, &order->progress, *step, count); + + /* check for cancel request */ + if (ecore_thread_check(thread)) + return EINA_FALSE; + } + + return EINA_TRUE; + + on_error: + eio_file_thread_error(&order->progress.common, thread); + return EINA_FALSE; +} + +static Eina_Bool +_eio_dir_chmod(Ecore_Thread *thread, Eio_Dir_Copy *order, + long long *step, long long count, + int length_source, int length_dest, + Eina_Bool rmdir_source) +{ + const char *dir; + char target[PATH_MAX]; + struct stat buffer; + + while(order->dirs) + { + /* destroy in reverse order so that we don't prevent change of lower dir */ + dir = eina_list_data_get(eina_list_last(order->dirs)); + order->dirs = eina_list_remove_list(order->dirs, eina_list_last(order->dirs)); + + /* build target dir path */ + _eio_dir_target(order, target, dir, length_source, length_dest); + + /* FIXME: in some case we already did a stat call, so would be nice to reuse previous result here */ + /* stat the original dir for mode info */ + if (stat(dir, &buffer) != 0) + goto on_error; + + /* set the orginal mode to the newly created dir */ + if (chmod(target, buffer.st_mode) != 0) + goto on_error; + + /* if required destroy original directory */ + if (rmdir_source) + { + if (rmdir(dir) != 0) + goto on_error; + } + + /* inform main thread */ + (*step)++; + eio_progress_send(thread, &order->progress, *step, count); + + /* check for cancel request */ + if (ecore_thread_check(thread)) + goto on_cancel; + + eina_stringshare_del(dir); + } + + return EINA_TRUE; + + on_error: + eio_file_thread_error(&order->progress.common, thread); + on_cancel: + if (dir) eina_stringshare_del(dir); + return EINA_FALSE; +} + +static void +_eio_dir_copy_heavy(void *data, Ecore_Thread *thread) +{ + Eio_Dir_Copy *copy = data; + const char *file = NULL; + const char *dir; + const char *ln; + + Eio_File_Progress file_copy; + char target[PATH_MAX]; + + int length_source = 0; + int length_dest = 0; + long long count; + long long step; + + /* list all the content that should be copied */ + if (!_eio_dir_recursiv_ls(thread, copy, copy->progress.source)) + return ; + + /* init all structure needed to copy the file */ + if (!_eio_dir_init(thread, &step, &count, &length_source, &length_dest, copy, &file_copy)) + goto on_error; + + /* suboperation is a file copy */ + file_copy.op = EIO_FILE_COPY; + + /* create all directory */ + if (!_eio_dir_mkdir(thread, copy, &step, count, length_source, length_dest)) + goto on_error; + + /* copy all files */ + EINA_LIST_FREE(copy->files, file) + { + /* build target file path */ + _eio_dir_target(copy, target, file, length_source, length_dest); + + file_copy.source = file; + file_copy.dest = eina_stringshare_add(target); + + /* copy the file */ + if (!eio_file_copy_do(thread, &file_copy)) + { + copy->progress.common.error = file_copy.common.error; + goto on_error; + } + + /* notify main thread */ + step++; + eio_progress_send(thread, ©->progress, step, count); + + if (ecore_thread_check(thread)) + goto on_error; + + eina_stringshare_del(file_copy.dest); + eina_stringshare_del(file); + } + file_copy.dest = NULL; + file = NULL; + + /* recreate link */ + if (!_eio_dir_link(thread, copy, &step, count, length_source, length_dest)) + goto on_error; + + /* set directory right back */ + if (!_eio_dir_chmod(thread, copy, &step, count, length_source, length_dest, EINA_FALSE)) + goto on_error; + + on_error: + /* cleanup the mess */ + if (file_copy.dest) eina_stringshare_del(file_copy.dest); + if (file) eina_stringshare_del(file); + + EINA_LIST_FREE(copy->files, file) + eina_stringshare_del(file); + EINA_LIST_FREE(copy->dirs, dir) + eina_stringshare_del(dir); + EINA_LIST_FREE(copy->links, ln) + eina_stringshare_del(ln); + + if (!ecore_thread_check(thread)) + eio_progress_send(thread, ©->progress, count, count); + + return ; +} + +static void +_eio_dir_copy_notify(void *data, Ecore_Thread *thread __UNUSED__, void *msg_data) +{ + Eio_Dir_Copy *copy = data; + Eio_Progress *progress = msg_data; + + eio_progress_cb(progress, ©->progress); +} + +static void +_eio_dir_copy_free(Eio_Dir_Copy *copy) +{ + eina_stringshare_del(copy->progress.source); + eina_stringshare_del(copy->progress.dest); + eio_file_free(©->progress.common); +} + +static void +_eio_dir_copy_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Dir_Copy *copy = data; + + copy->progress.common.done_cb((void*) copy->progress.common.data, ©->progress.common); + + _eio_dir_copy_free(copy); +} + +static void +_eio_dir_copy_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Dir_Copy *copy = data; + + eio_file_error(©->progress.common); + + _eio_dir_copy_free(copy); +} + +static void +_eio_dir_move_heavy(void *data, Ecore_Thread *thread) +{ + Eio_Dir_Copy *move = data; + const char *file = NULL; + const char *dir = NULL; + + Eio_File_Progress file_move; + char target[PATH_MAX]; + + int length_source; + int length_dest; + long long count; + long long step; + + /* just try a rename, maybe we are lucky... */ + if (rename(move->progress.source, move->progress.dest) == 0) + { + /* we are really lucky */ + eio_progress_send(thread, &move->progress, 1, 1); + return ; + } + + /* list all the content that should be moved */ + if (!_eio_dir_recursiv_ls(thread, move, move->progress.source)) + return ; + + /* init all structure needed to move the file */ + if (!_eio_dir_init(thread, &step, &count, &length_source, &length_dest, move, &file_move)) + goto on_error; + + /* sub operation is a file move */ + file_move.op = EIO_FILE_MOVE; + + /* create all directory */ + if (!_eio_dir_mkdir(thread, move, &step, count, length_source, length_dest)) + goto on_error; + + /* move file around */ + EINA_LIST_FREE(move->files, file) + { + /* build target file path */ + _eio_dir_target(move, target, file, length_source, length_dest); + + file_move.source = file; + file_move.dest = eina_stringshare_add(target); + + /* first try to rename */ + if (rename(file_move.source, file_move.dest) < 0) + { + if (errno != EXDEV) + { + eio_file_thread_error(&move->progress.common, thread); + goto on_error; + } + + /* then try real copy */ + if (!eio_file_copy_do(thread, &file_move)) + { + move->progress.common.error = file_move.common.error; + goto on_error; + } + + /* and unlink the original */ + if (unlink(file) != 0) + { + eio_file_thread_error(&move->progress.common, thread); + goto on_error; + } + } + + step++; + eio_progress_send(thread, &move->progress, step, count); + + if (ecore_thread_check(thread)) + goto on_error; + + eina_stringshare_del(file_move.dest); + eina_stringshare_del(file); + } + file_move.dest = NULL; + file = NULL; + + /* recreate link */ + if (!_eio_dir_link(thread, move, &step, count, length_source, length_dest)) + goto on_error; + + /* set directory right back */ + if (!_eio_dir_chmod(thread, move, &step, count, length_source, length_dest, EINA_TRUE)) + goto on_error; + + if (rmdir(move->progress.source) != 0) + goto on_error; + + on_error: + /* cleanup the mess */ + if (file_move.dest) eina_stringshare_del(file_move.dest); + if (file) eina_stringshare_del(file); + + EINA_LIST_FREE(move->files, file) + eina_stringshare_del(file); + EINA_LIST_FREE(move->dirs, dir) + eina_stringshare_del(dir); + + if (!ecore_thread_check(thread)) + eio_progress_send(thread, &move->progress, count, count); + + return; +} + +static void +_eio_dir_rmrf_heavy(void *data, Ecore_Thread *thread) +{ + Eio_Dir_Copy *rmrf = data; + const char *file = NULL; + const char *dir = NULL; + + long long count; + long long step; + + /* list all the content that should be moved */ + if (!_eio_dir_recursiv_ls(thread, rmrf, rmrf->progress.source)) + return ; + + /* init counter */ + step = 0; + count = eina_list_count(rmrf->files) + eina_list_count(rmrf->dirs) + 1; + + EINA_LIST_FREE(rmrf->files, file) + { + if (unlink(file) != 0) + { + eio_file_thread_error(&rmrf->progress.common, thread); + goto on_error; + } + + eina_stringshare_replace(&rmrf->progress.dest, file); + + step++; + eio_progress_send(thread, &rmrf->progress, step, count); + + if (ecore_thread_check(thread)) + goto on_error; + + eina_stringshare_del(file); + } + file = NULL; + + /* reverse directory listing, so the leaf would be destroyed before + the root */ + rmrf->dirs = eina_list_reverse(rmrf->dirs); + + EINA_LIST_FREE(rmrf->dirs, dir) + { + if (rmdir(dir) != 0) + { + eio_file_thread_error(&rmrf->progress.common, thread); + goto on_error; + } + + eina_stringshare_replace(&rmrf->progress.dest, dir); + + step++; + eio_progress_send(thread, &rmrf->progress, step, count); + + if (ecore_thread_check(thread)) + goto on_error; + + eina_stringshare_del(dir); + } + dir = NULL; + + if (rmdir(rmrf->progress.source) != 0) + goto on_error; + step++; + + on_error: + if (dir) eina_stringshare_del(dir); + if (file) eina_stringshare_del(file); + + EINA_LIST_FREE(rmrf->dirs, dir) + eina_stringshare_del(dir); + EINA_LIST_FREE(rmrf->files, file) + eina_stringshare_del(file); + + if (!ecore_thread_check(thread)) + eio_progress_send(thread, &rmrf->progress, count, count); + + return; +} + +static Eina_Bool +_eio_dir_stat_find_forward(Eio_File_Dir_Ls *async, + Eio_File *handler, + Eina_File_Direct_Info *info) +{ + Eina_Bool filter = EINA_TRUE; + double current; + + if (async->filter_cb) + { + filter = async->filter_cb((void*) async->ls.common.data, &async->ls.common, info); + } + + if (filter) + { + Eio_File_Direct_Info *send_di; + + send_di = eio_direct_info_malloc(); + if (!send_di) return EINA_FALSE; + + memcpy(&send_di->info, info, sizeof (Eina_File_Direct_Info)); + send_di->associated = async->ls.common.worker.associated; + async->ls.common.worker.associated = NULL; + + async->pack = eina_list_append(async->pack, send_di); + } + else if (async->ls.common.worker.associated) + { + eina_hash_free(async->ls.common.worker.associated); + async->ls.common.worker.associated = NULL; + } + + current = ecore_time_get(); + if (current - async->start > EIO_PACKED_TIME) + { + async->start = current; + ecore_thread_feedback(handler->thread, async->pack); + async->pack = NULL; + } + + return filter; +} + +static void +_eio_dir_stat_find_heavy(void *data, Ecore_Thread *thread) +{ + Eio_File_Dir_Ls *async = data; + + async->ls.common.thread = thread; + async->pack = NULL; + async->start = ecore_time_get(); + + _eio_file_recursiv_ls(thread, &async->ls.common, + (Eio_Filter_Direct_Cb) _eio_dir_stat_find_forward, + eina_file_stat_ls, + async, async->ls.directory); + + if (async->pack) ecore_thread_feedback(thread, async->pack); + async->pack = NULL; +} + +static void +_eio_dir_direct_find_heavy(void *data, Ecore_Thread *thread) +{ + Eio_File_Dir_Ls *async = data; + + async->ls.common.thread = thread; + async->pack = NULL; + async->start = ecore_time_get(); + + _eio_file_recursiv_ls(thread, &async->ls.common, + (Eio_Filter_Direct_Cb) _eio_dir_stat_find_forward, + eina_file_direct_ls, + async, async->ls.directory); + + if (async->pack) ecore_thread_feedback(thread, async->pack); + async->pack = NULL; +} + +static void +_eio_dir_stat_find_notify(void *data, Ecore_Thread *thread __UNUSED__, void *msg_data) +{ + Eio_File_Dir_Ls *async = data; + Eina_List *pack = msg_data; + Eio_File_Direct_Info *info; + + EINA_LIST_FREE(pack, info) + { + async->ls.common.main.associated = info->associated; + + async->main_cb((void*) async->ls.common.data, &async->ls.common, &info->info); + + if (async->ls.common.main.associated) + { + eina_hash_free(async->ls.common.main.associated); + async->ls.common.main.associated = NULL; + } + + eio_direct_info_free(info); + } +} + +static void +_eio_dir_stat_done(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Ls *async = data; + + async->common.done_cb((void*) async->common.data, &async->common); + + eio_async_free(async); +} + +static void +_eio_dir_stat_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Ls *async = data; + + eio_file_error(&async->common); + + eio_async_free(async); +} + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + + +/*============================================================================* + * API * + *============================================================================*/ + + +EAPI Eio_File * +eio_dir_copy(const char *source, + const char *dest, + Eio_Filter_Direct_Cb filter_cb, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_Dir_Copy *copy; + + EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + copy = malloc(sizeof(Eio_Dir_Copy)); + EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL); + + copy->progress.op = EIO_DIR_COPY; + copy->progress.progress_cb = progress_cb; + copy->progress.source = eina_stringshare_add(source); + copy->progress.dest = eina_stringshare_add(dest); + copy->filter_cb = filter_cb; + copy->files = NULL; + copy->dirs = NULL; + copy->links = NULL; + + if (!eio_long_file_set(©->progress.common, + done_cb, + error_cb, + data, + _eio_dir_copy_heavy, + _eio_dir_copy_notify, + _eio_dir_copy_end, + _eio_dir_copy_error)) + return NULL; + + return ©->progress.common; +} + +EAPI Eio_File * +eio_dir_move(const char *source, + const char *dest, + Eio_Filter_Direct_Cb filter_cb, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_Dir_Copy *move; + + EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + move = malloc(sizeof(Eio_Dir_Copy)); + EINA_SAFETY_ON_NULL_RETURN_VAL(move, NULL); + + move->progress.op = EIO_DIR_MOVE; + move->progress.progress_cb = progress_cb; + move->progress.source = eina_stringshare_add(source); + move->progress.dest = eina_stringshare_add(dest); + move->filter_cb = filter_cb; + move->files = NULL; + move->dirs = NULL; + move->links = NULL; + + if (!eio_long_file_set(&move->progress.common, + done_cb, + error_cb, + data, + _eio_dir_move_heavy, + _eio_dir_copy_notify, + _eio_dir_copy_end, + _eio_dir_copy_error)) + return NULL; + + return &move->progress.common; +} + +EAPI Eio_File * +eio_dir_unlink(const char *path, + Eio_Filter_Direct_Cb filter_cb, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_Dir_Copy *rmrf; + + EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + rmrf = malloc(sizeof(Eio_Dir_Copy)); + EINA_SAFETY_ON_NULL_RETURN_VAL(rmrf, NULL); + + rmrf->progress.op = EIO_UNLINK; + rmrf->progress.progress_cb = progress_cb; + rmrf->progress.source = eina_stringshare_add(path); + rmrf->progress.dest = NULL; + rmrf->filter_cb = filter_cb; + rmrf->files = NULL; + rmrf->dirs = NULL; + rmrf->links = NULL; + + if (!eio_long_file_set(&rmrf->progress.common, + done_cb, + error_cb, + data, + _eio_dir_rmrf_heavy, + _eio_dir_copy_notify, + _eio_dir_copy_end, + _eio_dir_copy_error)) + return NULL; + + return &rmrf->progress.common; +} + +EAPI Eio_File * +eio_dir_stat_ls(const char *dir, + Eio_Filter_Direct_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Dir_Ls *async; + + EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + async = malloc(sizeof(Eio_File_Dir_Ls)); + EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL); + + /* Eio_Filter_Direct_Cb must be casted to Eio_Filter_Dir_Cb here + * because we keep the Eio_File_Dir_Ls pointing to that variant + * where info can be modified, but in our case it's already doing + * stat() then it shouldn't be needed! + */ + async->filter_cb = (Eio_Filter_Dir_Cb)filter_cb; + async->main_cb = main_cb; + async->ls.directory = eina_stringshare_add(dir); + + if (!eio_long_file_set(&async->ls.common, + done_cb, + error_cb, + data, + _eio_dir_stat_find_heavy, + _eio_dir_stat_find_notify, + _eio_dir_stat_done, + _eio_dir_stat_error)) + return NULL; + + return &async->ls.common; +} + +EAPI Eio_File * +eio_dir_direct_ls(const char *dir, + Eio_Filter_Dir_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Dir_Ls *async; + + EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + async = malloc(sizeof(Eio_File_Dir_Ls)); + EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL); + + async->filter_cb = filter_cb; + async->main_cb = main_cb; + async->ls.directory = eina_stringshare_add(dir); + + if (!eio_long_file_set(&async->ls.common, + done_cb, + error_cb, + data, + _eio_dir_direct_find_heavy, + _eio_dir_stat_find_notify, + _eio_dir_stat_done, + _eio_dir_stat_error)) + return NULL; + + return &async->ls.common; +} diff --git a/src/lib/eio_eet.c b/src/lib/eio_eet.c new file mode 100644 index 0000000..049c1e3 --- /dev/null +++ b/src/lib/eio_eet.c @@ -0,0 +1,640 @@ +/* EIO - EFL data type library + * Copyright (C) 2010 Enlightenment Developers: + * Cedric Bail + * Vincent "caro" Torri + * Stephen "okra" Houston + * + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +static void +_eio_eet_open_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Open *eet = data; + + eet->result = eet_open(eet->filename, eet->mode); + if (!eet->result) eio_file_thread_error(&eet->common, thread); +} + +static void +_eio_eet_open_free(Eio_Eet_Open *eet) +{ + if (eet->filename) eina_stringshare_del(eet->filename); + free(eet); +} + +static void +_eio_eet_open_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Open *eet = data; + + eet->eet_cb((void*) eet->common.data, &eet->common, eet->result); + _eio_eet_open_free(eet); +} + +static void +_eio_eet_open_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Open *eet = data; + + eio_file_error(&eet->common); + _eio_eet_open_free(eet); +} + +static void +_eio_eet_close_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Simple *eet = data; + + eet->error = eet_close(eet->ef); + if (eet->error != EET_ERROR_NONE) eio_file_thread_error(&eet->common, thread); +} + +static void +_eio_eet_sync_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Simple *eet = data; + + eet->error = eet_sync(eet->ef); + if (eet->error != EET_ERROR_NONE) eio_file_thread_error(&eet->common, thread); +} + +static void +_eio_eet_simple_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Simple *eet = data; + + eet->common.done_cb((void*) eet->common.data, &eet->common); + free(eet); +} + +static void +_eio_eet_simple_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Simple *eet = data; + + eet->error_cb((void*) eet->common.data, &eet->common, eet->error); + free(eet); +} + +static void +_eio_eet_data_write_cipher_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Write *ew = data; + + ew->result = eet_data_write_cipher(ew->ef, ew->edd, + ew->name, ew->cipher_key, + ew->write_data, + ew->compress); + if (ew->result == 0) eio_file_thread_error(&ew->common, thread); +} + +static void +_eio_eet_write_cipher_free(Eio_Eet_Write *ew) +{ + eina_stringshare_del(ew->name); + eina_stringshare_del(ew->cipher_key); + free(ew); +} + +static void +_eio_eet_data_write_cipher_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Write *ew = data; + + ew->done_cb((void*) ew->common.data, &ew->common, ew->result); + _eio_eet_write_cipher_free(ew); +} + +static void +_eio_eet_data_write_cipher_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Write *ew = data; + + eio_file_error(&ew->common); + _eio_eet_write_cipher_free(ew); +} + +static void +_eio_eet_image_write_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Image_Write *eiw = data; + + eiw->result = eet_data_image_write_cipher(eiw->ef, eiw->name, eiw->cipher_key, + eiw->write_data, + eiw->w, + eiw->h, + eiw->alpha, + eiw->compress, + eiw->quality, + eiw->lossy); + if (!eiw->result) eio_file_thread_error(&eiw->common, thread); +} + +static void +_eio_eet_image_write_free(Eio_Eet_Image_Write *eiw) +{ + eina_stringshare_del(eiw->name); + eina_stringshare_del(eiw->cipher_key); + free(eiw); +} + +static void +_eio_eet_image_write_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Image_Write *eiw = data; + + eiw->done_cb((void*) eiw->common.data, &eiw->common, eiw->result); + _eio_eet_image_write_free(eiw); +} + +static void +_eio_eet_image_write_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Image_Write *eiw = data; + + eio_file_error(&eiw->common); + _eio_eet_image_write_free(eiw); +} + +static void +_eio_eet_write_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Write *ew = data; + + ew->result = eet_write_cipher(ew->ef, + ew->name, ew->write_data, + ew->size, ew->compress, + ew->cipher_key); + if (!ew->result) eio_file_thread_error(&ew->common, thread); +} + +static void +_eio_eet_write_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Write *ew = data; + + ew->done_cb((void*) ew->common.data, &ew->common, ew->result); + _eio_eet_write_cipher_free(ew); +} + +static void +_eio_eet_write_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Write *ew = data; + + eio_file_error(&ew->common); + _eio_eet_write_cipher_free(ew); +} + +static void +_eio_eet_data_read_cipher_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Read *er = data; + + er->result = eet_data_read_cipher(er->ef, er->edd, + er->name, er->cipher_key); + if (!er->result) eio_file_thread_error(&er->common, thread); +} + +static void +_eio_eet_read_free(Eio_Eet_Read *er) +{ + eina_stringshare_del(er->name); + eina_stringshare_del(er->cipher_key); + free(er); +} + +static void +_eio_eet_data_read_cipher_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Read *er = data; + + er->done_cb.eread((void*) er->common.data, &er->common, er->result); + _eio_eet_read_free(er); +} + +static void +_eio_eet_data_read_cipher_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Read *er = data; + + eio_file_error(&er->common); + _eio_eet_read_free(er); +} + +static void +_eio_eet_read_direct_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Read *er = data; + + er->result = (void*) eet_read_direct(er->ef, er->name, &er->size); + if (!er->result) eio_file_thread_error(&er->common, thread); +} + +static void +_eio_eet_read_direct_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Read *er = data; + + er->done_cb.data((void*) er->common.data, &er->common, + er->result, er->size); + _eio_eet_read_free(er); +} + +static void +_eio_eet_read_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Read *er = data; + + eio_file_error(&er->common); + _eio_eet_read_free(er); +} + +static void +_eio_eet_read_cipher_job(void *data, Ecore_Thread *thread) +{ + Eio_Eet_Read *er = data; + + er->result = (void*) eet_read_cipher(er->ef, er->name, + &er->size, er->cipher_key); + if (!er->result) eio_file_thread_error(&er->common, thread); +} + +static void +_eio_eet_read_cipher_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Eet_Read *er = data; + + er->done_cb.read((void*) er->common.data, &er->common, + er->result, er->size); + _eio_eet_read_free(er); +} + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI Eio_File * +eio_eet_open(const char *filename, + Eet_File_Mode mode, + Eio_Eet_Open_Cb eet_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_Eet_Open *eet; + + EINA_SAFETY_ON_NULL_RETURN_VAL(filename, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(eet_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + eet = malloc(sizeof (Eio_Eet_Open)); + EINA_SAFETY_ON_NULL_RETURN_VAL(eet, NULL); + + eet->eet_cb = eet_cb; + eet->filename = eina_stringshare_add(filename); + eet->mode = mode; + eet->result = NULL; + + if (!eio_file_set(&eet->common, + NULL, + error_cb, + data, + _eio_eet_open_job, + _eio_eet_open_end, + _eio_eet_open_cancel)) + return NULL; + return &eet->common; +} + +EAPI Eio_File * +eio_eet_close(Eet_File *ef, + Eio_Done_Cb done_cb, + Eio_Eet_Error_Cb error_cb, + const void *data) +{ + Eio_Eet_Simple *eet; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + eet = malloc(sizeof (Eio_Eet_Simple)); + EINA_SAFETY_ON_NULL_RETURN_VAL(eet, NULL); + + eet->ef = ef; + eet->error_cb = error_cb; + eet->error = EET_ERROR_NONE; + + if (!eio_file_set(&eet->common, + done_cb, + NULL, + data, + _eio_eet_close_job, + _eio_eet_simple_end, + _eio_eet_simple_cancel)) + return NULL; + return &eet->common; +} + +EAPI Eio_File * +eio_eet_flush(Eet_File *ef, + Eio_Done_Cb done_cb, + Eio_Eet_Error_Cb error_cb, + const void *data) +{ + Eio_Eet_Simple *eet; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + eet = malloc(sizeof (Eio_Eet_Simple)); + EINA_SAFETY_ON_NULL_RETURN_VAL(eet, NULL); + + eet->ef = ef; + eet->error_cb = error_cb; + eet->error = EET_ERROR_NONE; + + if (!eio_file_set(&eet->common, + done_cb, + NULL, + data, + _eio_eet_sync_job, + _eio_eet_simple_end, + _eio_eet_simple_cancel)) + return NULL; + return &eet->common; +} + +EAPI Eio_File * +eio_eet_data_write_cipher(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name, + const char *cipher_key, + void *write_data, + int compress, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *user_data) +{ + Eio_Eet_Write *ew; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(edd, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + ew = malloc(sizeof (Eio_Eet_Write)); + EINA_SAFETY_ON_NULL_RETURN_VAL(ew, NULL); + + ew->ef = ef; + ew->edd = edd; + ew->name = eina_stringshare_add(name); + ew->cipher_key = eina_stringshare_add(cipher_key); + ew->write_data = write_data; + ew->compress = compress; + ew->done_cb = done_cb; + ew->result = 0; + + if (!eio_file_set(&ew->common, + NULL, + error_cb, + user_data, + _eio_eet_data_write_cipher_job, + _eio_eet_data_write_cipher_end, + _eio_eet_data_write_cipher_cancel)) + return NULL; + return &ew->common; +} + +EAPI Eio_File * +eio_eet_data_read_cipher(Eet_File *ef, + Eet_Data_Descriptor *edd, + const char *name, + const char *cipher_key, + Eio_Done_ERead_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_Eet_Read *er; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(edd, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + er = malloc(sizeof (Eio_Eet_Read)); + EINA_SAFETY_ON_NULL_RETURN_VAL(er, NULL); + + er->ef = ef; + er->edd = edd; + er->name = eina_stringshare_add(name); + er->cipher_key = eina_stringshare_add(cipher_key); + er->done_cb.eread = done_cb; + + if (!eio_file_set(&er->common, + NULL, + error_cb, + data, + _eio_eet_data_read_cipher_job, + _eio_eet_data_read_cipher_end, + _eio_eet_data_read_cipher_cancel)) + return NULL; + + return &er->common; +} + +EAPI Eio_File * +eio_eet_data_image_write_cipher(Eet_File *ef, + const char *name, + const char *cipher_key, + void *write_data, + unsigned int w, + unsigned int h, + int alpha, + int compress, + int quality, + int lossy, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *user_data) +{ + Eio_Eet_Image_Write *eiw; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + eiw = malloc(sizeof (Eio_Eet_Image_Write)); + EINA_SAFETY_ON_NULL_RETURN_VAL(eiw, NULL); + + eiw->ef = ef; + eiw->name = eina_stringshare_add(name); + eiw->cipher_key = eina_stringshare_add(cipher_key); + eiw->write_data = write_data; + eiw->w = w; + eiw->h = h; + eiw->alpha = alpha; + eiw->compress = compress; + eiw->quality = quality; + eiw->lossy = lossy; + eiw->done_cb = done_cb; + eiw->result = 0; + + if (!eio_file_set(&eiw->common, + NULL, + error_cb, + user_data, + _eio_eet_image_write_job, + _eio_eet_image_write_end, + _eio_eet_image_write_cancel)) + return NULL; + return &eiw->common; +} + +EAPI Eio_File * +eio_eet_read_direct(Eet_File *ef, + const char *name, + Eio_Done_Data_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_Eet_Read *er; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + er = malloc(sizeof (Eio_Eet_Read)); + EINA_SAFETY_ON_NULL_RETURN_VAL(er, NULL); + + er->ef = ef; + er->name = eina_stringshare_add(name); + er->cipher_key = NULL; + er->done_cb.data = done_cb; + er->result = NULL; + + if (!eio_file_set(&er->common, + NULL, + error_cb, + data, + _eio_eet_read_direct_job, + _eio_eet_read_direct_end, + _eio_eet_read_cancel)) + return NULL; + + return &er->common; +} + +EAPI Eio_File * +eio_eet_read_cipher(Eet_File *ef, + const char *name, + const char *cipher_key, + Eio_Done_Read_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_Eet_Read *er; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + er = malloc(sizeof (Eio_Eet_Read)); + EINA_SAFETY_ON_NULL_RETURN_VAL(er, NULL); + + er->ef = ef; + er->name = eina_stringshare_add(name); + er->cipher_key = eina_stringshare_add(cipher_key); + er->done_cb.read = done_cb; + er->result = NULL; + + if (!eio_file_set(&er->common, + NULL, + error_cb, + data, + _eio_eet_read_cipher_job, + _eio_eet_read_cipher_end, + _eio_eet_read_cancel)) + return NULL; + return &er->common; +} + +EAPI Eio_File * +eio_eet_write_cipher(Eet_File *ef, + const char *name, + void *write_data, + int size, + int compress, + const char *cipher_key, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *user_data) +{ + Eio_Eet_Write *ew; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ef, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + ew = malloc(sizeof (Eio_Eet_Write)); + EINA_SAFETY_ON_NULL_RETURN_VAL(ew, NULL); + + ew->ef = ef; + ew->name = eina_stringshare_add(name); + ew->cipher_key = eina_stringshare_add(cipher_key); + ew->write_data = write_data; + ew->size = size; + ew->compress = compress; + ew->done_cb = done_cb; + ew->result = 0; + + if (!eio_file_set(&ew->common, + NULL, + error_cb, + user_data, + _eio_eet_write_job, + _eio_eet_write_end, + _eio_eet_write_cancel)) + return NULL; + return &ew->common; +} diff --git a/src/lib/eio_file.c b/src/lib/eio_file.c index bf5c197..31122d0 100644 --- a/src/lib/eio_file.c +++ b/src/lib/eio_file.c @@ -2,6 +2,7 @@ * Copyright (C) 2010 Enlightenment Developers: * Cedric Bail * Vincent "caro" Torri + * Stephen "okra" Houston * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -18,240 +19,961 @@ * if not, see . */ -#ifdef HAVE_CONFIG_H -# include "config.h" +#include "eio_private.h" +#include "Eio.h" + +#ifdef HAVE_XATTR +# include #endif -#include +/*============================================================================* + * Local * + *============================================================================*/ -#include "Eio.h" - -struct _Eio_List -{ - Eina_Iterator *it; - Ecore_Thread *thread; - const void *data; - - Eio_Done_Cb done; - - union - { - struct - { - Eio_Filter_Direct_Cb filter; - Eio_Main_Direct_Cb main; - } direct; - struct - { - Eio_Filter_Cb filter; - Eio_Main_Cb main; - } str; - } u; -}; - -static int _eio_count = 0; +/** + * @cond LOCAL + */ static void -_eio_file_heavy(Ecore_Thread *thread, void *data) +_eio_file_heavy(void *data, Ecore_Thread *thread) { - Eio_List *async; + Eio_File_Char_Ls *async = data; + Eina_Iterator *ls; const char *file; + Eina_List *pack = NULL; + double start, current; + + ls = eina_file_ls(async->ls.directory); + if (!ls) + { + eio_file_thread_error(&async->ls.common, thread); + return ; + } + + eio_file_container_set(&async->ls.common, eina_iterator_container_get(ls)); - async = data; + start = ecore_time_get(); - EINA_ITERATOR_FOREACH(async->it, file) + EINA_ITERATOR_FOREACH(ls, file) { Eina_Bool filter = EINA_TRUE; - if (async->u.str.filter) + if (async->filter_cb) { - filter = async->u.str.filter(file, (void*) async->data); + filter = async->filter_cb((void*) async->ls.common.data, &async->ls.common, file); } - if (filter) ecore_thread_notify(thread, file); - else eina_stringshare_del(file); + if (filter) + { + Eio_File_Char *send_fc; + + send_fc = eio_char_malloc(); + if (!send_fc) goto on_error; + + send_fc->filename = file; + send_fc->associated = async->ls.common.worker.associated; + async->ls.common.worker.associated = NULL; + + pack = eina_list_append(pack, send_fc); + } + else + { + on_error: + eina_stringshare_del(file); + + if (async->ls.common.worker.associated) + { + eina_hash_free(async->ls.common.worker.associated); + async->ls.common.worker.associated = NULL; + } + } + + current = ecore_time_get(); + if (current - start > EIO_PACKED_TIME) + { + start = current; + ecore_thread_feedback(thread, pack); + pack = NULL; + } + + if (ecore_thread_check(thread)) + break; } + + if (pack) ecore_thread_feedback(thread, pack); + + eio_file_container_set(&async->ls.common, NULL); + + eina_iterator_free(ls); } static void -_eio_file_notify(__UNUSED__ Ecore_Thread *thread, void *msg_data, void *data) +_eio_file_notify(void *data, Ecore_Thread *thread __UNUSED__, void *msg_data) { - Eio_List *async; - const char *file; + Eio_File_Char_Ls *async = data; + Eina_List *pack = msg_data; + Eio_File_Char *info; - async = data; - file = msg_data; + EINA_LIST_FREE(pack, info) + { + async->ls.common.main.associated = info->associated; - if (async->u.str.main) - async->u.str.main(file, (void*) async->data); + async->main_cb((void*) async->ls.common.data, + &async->ls.common, + info->filename); - eina_stringshare_del(file); + if (async->ls.common.main.associated) + { + eina_hash_free(async->ls.common.main.associated); + async->ls.common.main.associated = NULL; + } + + eina_stringshare_del(info->filename); + eio_char_free(info); + } } static void -_eio_file_direct_heavy(Ecore_Thread *thread, void *data) +_eio_file_eina_ls_heavy(Ecore_Thread *thread, Eio_File_Direct_Ls *async, Eina_Iterator *ls) { - Eio_List *async; const Eina_File_Direct_Info *info; + Eina_List *pack = NULL; + double start, current; + + if (!ls) + { + eio_file_thread_error(&async->ls.common, thread); + return ; + } + + eio_file_container_set(&async->ls.common, eina_iterator_container_get(ls)); - async = data; + start = ecore_time_get(); - EINA_ITERATOR_FOREACH(async->it, info) + EINA_ITERATOR_FOREACH(ls, info) { Eina_Bool filter = EINA_TRUE; - if (async->u.direct.filter) + if (async->filter_cb) { - filter = async->u.direct.filter(info, (void*) async->data); + filter = async->filter_cb((void*) async->ls.common.data, &async->ls.common, info); } if (filter) { - Eina_File_Direct_Info *send; + Eio_File_Direct_Info *send_di; - send = malloc(sizeof (Eina_File_Direct_Info)); - if (!send) continue; + send_di = eio_direct_info_malloc(); + if (!send_di) continue; - memcpy(send, info, sizeof (Eina_File_Direct_Info)); - ecore_thread_notify(thread, send); + memcpy(&send_di->info, info, sizeof (Eina_File_Direct_Info)); + send_di->associated = async->ls.common.worker.associated; + async->ls.common.worker.associated = NULL; + + pack = eina_list_append(pack, send_di); + } + else if (async->ls.common.worker.associated) + { + eina_hash_free(async->ls.common.worker.associated); + async->ls.common.worker.associated = NULL; } + + current = ecore_time_get(); + if (current - start > EIO_PACKED_TIME) + { + start = current; + ecore_thread_feedback(thread, pack); + pack = NULL; + } + + if (ecore_thread_check(thread)) + break; } + + if (pack) ecore_thread_feedback(thread, pack); + + eio_file_container_set(&async->ls.common, NULL); + + eina_iterator_free(ls); } static void -_eio_file_direct_notify(__UNUSED__ Ecore_Thread *thread, void *msg_data, void *data) +_eio_file_direct_heavy(void *data, Ecore_Thread *thread) { - Eio_List *async; - Eina_File_Direct_Info *info; + Eio_File_Direct_Ls *async = data; + Eina_Iterator *ls; - async = data; - info = msg_data; + ls = eina_file_direct_ls(async->ls.directory); - if (async->u.direct.main) - async->u.direct.main(info, (void*) async->data); + _eio_file_eina_ls_heavy(thread, async, ls); +} - free(info); +static void +_eio_file_stat_heavy(void *data, Ecore_Thread *thread) +{ + Eio_File_Direct_Ls *async = data; + Eina_Iterator *ls; + + ls = eina_file_stat_ls(async->ls.directory); + + _eio_file_eina_ls_heavy(thread, async, ls); } static void -_eio_file_end(void *data) +_eio_file_direct_notify(void *data, Ecore_Thread *thread __UNUSED__, void *msg_data) { - Eio_List *async; + Eio_File_Direct_Ls *async = data; + Eina_List *pack = msg_data; + Eio_File_Direct_Info *info; - async = data; + EINA_LIST_FREE(pack, info) + { + async->ls.common.main.associated = info->associated; - if (async->done) - async->done((void*) async->data); + async->main_cb((void*) async->ls.common.data, + &async->ls.common, + &info->info); + + if (async->ls.common.main.associated) + { + eina_hash_free(async->ls.common.main.associated); + async->ls.common.main.associated = NULL; + } + + eio_direct_info_free(info); + } +} + +static void +_eio_eina_file_copy_xattr(Ecore_Thread *thread __UNUSED__, + Eio_File_Progress *op __UNUSED__, + Eina_File *f, int out) +{ + Eina_Iterator *it; + Eina_Xattr *attr; - eina_iterator_free(async->it); - free(async); + it = eina_file_xattr_value_get(f); + EINA_ITERATOR_FOREACH(it, attr) + { +#ifdef HAVE_XATTR + fsetxattr(out, attr->name, attr->value, attr->length, 0); +#endif + } + eina_iterator_free(it); } -EAPI int -eio_init(void) +#ifdef HAVE_XATTR +static void +_eio_file_copy_xattr(Ecore_Thread *thread __UNUSED__, + Eio_File_Progress *op __UNUSED__, + int in, int out) { - _eio_count++; + char *tmp; + ssize_t length; + ssize_t i; + + length = flistxattr(in, NULL, 0); + + if (length <= 0) return ; + + tmp = alloca(length); + length = flistxattr(in, tmp, length); + + for (i = 0; i < length; i += strlen(tmp) + 1) + { + ssize_t attr_length; + void *value; - if (_eio_count > 1) return _eio_count; + attr_length = fgetxattr(in, tmp, NULL, 0); + if (!attr_length) continue ; - eina_init(); - ecore_init(); + value = malloc(attr_length); + if (!value) continue ; + attr_length = fgetxattr(in, tmp, value, attr_length); - return _eio_count; + if (attr_length > 0) + fsetxattr(out, tmp, value, attr_length, 0); + + free(value); + } } +#endif -EAPI int -eio_shutdown(void) +static Eina_Bool +_eio_file_write(int fd, void *mem, ssize_t length) { - _eio_count--; + ssize_t count; - if (_eio_count > 0) return _eio_count; + if (length == 0) return EINA_TRUE; - ecore_shutdown(); - eina_shutdown(); - return _eio_count; + count = write(fd, mem, length); + if (count != length) return EINA_FALSE; + return EINA_TRUE; } -EAPI Eio_List * -eio_file_ls(const char *dir, - Eio_Filter_Cb filter, - Eio_Main_Cb main, - Eio_Done_Cb done, - const void *data) +#ifndef MAP_HUGETLB +# define MAP_HUGETLB 0 +#endif + +static Eina_Bool +_eio_file_copy_mmap(Ecore_Thread *thread, Eio_File_Progress *op, Eina_File *f, int out) { - Eina_Iterator *ls; - Eio_List *async = NULL; + char *m = MAP_FAILED; + long long i; + long long size; - ls = eina_file_ls(dir); - if (!ls) return NULL; + size = eina_file_size_get(f); - async = malloc(sizeof (Eio_List)); - if (!async) goto on_error; + for (i = 0; i < size; i += EIO_PACKET_SIZE * EIO_PACKET_COUNT) + { + int j; + int k; + int c; + + m = eina_file_map_new(f, EINA_FILE_SEQUENTIAL, + i, EIO_PACKET_SIZE * EIO_PACKET_COUNT); + if (!m) + goto on_error; + + c = size - i; + if (c - EIO_PACKET_SIZE * EIO_PACKET_COUNT > 0) + c = EIO_PACKET_SIZE * EIO_PACKET_COUNT; + else + c = size - i; + + for (j = EIO_PACKET_SIZE, k = 0; j < c; k = j, j += EIO_PACKET_SIZE) + { + if (!_eio_file_write(out, m + k, EIO_PACKET_SIZE)) + goto on_error; + + eio_progress_send(thread, op, i + j, size); + } - async->u.str.filter = filter; - async->u.str.main = main; - async->done = done; - async->data = data; - async->it = ls; - async->thread = ecore_long_run(_eio_file_heavy, - _eio_file_notify, - _eio_file_end, - _eio_file_end, - async, - EINA_FALSE); - if (!async->thread) goto on_error; + if (!_eio_file_write(out, m + k, c - k)) + goto on_error; - return async; + if (eina_file_map_faulted(f, m)) + goto on_error; + eio_progress_send(thread, op, i + c, size); + + eina_file_map_free(f, m); + m = NULL; + + if (ecore_thread_check(thread)) + goto on_error; + } + + return EINA_TRUE; on_error: - free(async); - eina_iterator_free(ls); - return NULL; + if (m != NULL) eina_file_map_free(f, m); + return EINA_FALSE; } -EAPI Eio_List * -eio_file_direct_ls(const char *dir, - Eio_Filter_Direct_Cb filter, - Eio_Main_Direct_Cb main, - Eio_Done_Cb done, - const void *data) +#ifdef HAVE_SPLICE +static int +_eio_file_copy_splice(Ecore_Thread *thread, Eio_File_Progress *op, int in, int out, long long size) { - Eina_Iterator *ls; - Eio_List *async = NULL; + int result = 0; + long long count; + long long i; + int pipefd[2]; + + if (pipe(pipefd) < 0) + return -1; - ls = eina_file_direct_ls(dir); - if (!ls) return NULL; + for (i = 0; i < size; i += count) + { + count = splice(in, 0, pipefd[1], NULL, EIO_PACKET_SIZE * EIO_PACKET_COUNT, SPLICE_F_MORE | SPLICE_F_MOVE); + if (count < 0) goto on_error; - async = malloc(sizeof (Eio_List)); - if (!async) goto on_error; + count = splice(pipefd[0], NULL, out, 0, count, SPLICE_F_MORE | SPLICE_F_MOVE); + if (count < 0) goto on_error; - async->u.direct.filter = filter; - async->u.direct.main = main; - async->done = done; - async->data = data; - async->it = ls; - async->thread = ecore_long_run(_eio_file_direct_heavy, - _eio_file_direct_notify, - _eio_file_end, - _eio_file_end, - async, - EINA_FALSE); - if (!async->thread) goto on_error; + eio_progress_send(thread, op, i, size); - return async; + if (ecore_thread_check(thread)) + goto on_error; + } + result = 1; on_error: - free(async); - eina_iterator_free(ls); - return NULL; + if (result != 1 && (errno == EBADF || errno == EINVAL)) result = -1; + close(pipefd[0]); + close(pipefd[1]); + + return result; +} +#endif + +static void +_eio_file_copy_heavy(void *data, Ecore_Thread *thread) +{ + Eio_File_Progress *copy = data; + + eio_file_copy_do(thread, copy); +} + +static void +_eio_file_copy_notify(void *data, Ecore_Thread *thread __UNUSED__, void *msg_data) +{ + Eio_File_Progress *copy = data; + + eio_progress_cb(msg_data, copy); +} + +static void +_eio_file_copy_free(Eio_File_Progress *copy) +{ + eina_stringshare_del(copy->source); + eina_stringshare_del(copy->dest); + eio_file_free(©->common); +} + +static void +_eio_file_copy_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Progress *copy = data; + + copy->common.done_cb((void*) copy->common.data, ©->common); + + _eio_file_copy_free(copy); +} + +static void +_eio_file_copy_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Progress *copy = data; + + eio_file_error(©->common); + + _eio_file_copy_free(copy); +} + +static void +_eio_file_move_free(Eio_File_Move *move) +{ + eina_stringshare_del(move->progress.source); + eina_stringshare_del(move->progress.dest); + eio_file_free(&move->progress.common); +} + +static void +_eio_file_move_copy_progress(void *data, Eio_File *handler __UNUSED__, const Eio_Progress *info) +{ + Eio_File_Move *move = data; + + move->progress.progress_cb((void*) move->progress.common.data, &move->progress.common, info); +} + +static void +_eio_file_move_unlink_done(void *data, Eio_File *handler __UNUSED__) +{ + Eio_File_Move *move = data; + + move->progress.common.done_cb((void*) move->progress.common.data, &move->progress.common); + + _eio_file_move_free(move); +} + +static void +_eio_file_move_unlink_error(void *data, Eio_File *handler __UNUSED__, int error) +{ + Eio_File_Move *move = data; + + move->copy = NULL; + + move->progress.common.error = error; + eio_file_error(&move->progress.common); + + _eio_file_move_free(move); +} + +static void +_eio_file_move_copy_done(void *data, Eio_File *handler __UNUSED__) +{ + Eio_File_Move *move = data; + Eio_File *rm; + + rm = eio_file_unlink(move->progress.source, + _eio_file_move_unlink_done, + _eio_file_move_unlink_error, + move); + if (rm) move->copy = rm; +} + +static void +_eio_file_move_copy_error(void *data, Eio_File *handler __UNUSED__, int error) +{ + Eio_File_Move *move = data; + + move->progress.common.error = error; + eio_file_error(&move->progress.common); + + _eio_file_move_free(move); +} + +static void +_eio_file_move_heavy(void *data, Ecore_Thread *thread) +{ + Eio_File_Move *move = data; + + if (rename(move->progress.source, move->progress.dest) < 0) + eio_file_thread_error(&move->progress.common, thread); + else + eio_progress_send(thread, &move->progress, 1, 1); +} + +static void +_eio_file_move_notify(void *data, Ecore_Thread *thread __UNUSED__, void *msg_data) +{ + Eio_File_Move *move = data; + + eio_progress_cb(msg_data, &move->progress); +} + +static void +_eio_file_move_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Move *move = data; + + move->progress.common.done_cb((void*) move->progress.common.data, &move->progress.common); + + _eio_file_move_free(move); +} + +static void +_eio_file_move_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Move *move = data; + + if (move->copy) + { + eio_file_cancel(move->copy); + return ; + } + + if (move->progress.common.error == EXDEV) + { + Eio_File *eio_cp; + + eio_cp = eio_file_copy(move->progress.source, move->progress.dest, + move->progress.progress_cb ? _eio_file_move_copy_progress : NULL, + _eio_file_move_copy_done, + _eio_file_move_copy_error, + move); + + if (eio_cp) + { + move->copy = eio_cp; + + move->progress.common.thread = ((Eio_File_Progress*)move->copy)->common.thread; + return ; + } + } + + eio_file_error(&move->progress.common); + + _eio_file_move_free(move); +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +void +eio_progress_cb(Eio_Progress *progress, Eio_File_Progress *op) +{ + op->progress_cb((void *) op->common.data, &op->common, progress); + + eio_progress_free(progress); +} + +Eina_Bool +eio_file_copy_do(Ecore_Thread *thread, Eio_File_Progress *copy) +{ + Eina_File *f; +#ifdef HAVE_SPLICE + struct stat buf; + int in = -1; +#endif + mode_t md; + int result = -1; + int out = -1; + +#ifdef HAVE_SPLICE + in = open(copy->source, O_RDONLY); + if (in < 0) + { + eio_file_thread_error(©->common, thread); + return EINA_FALSE; + } + + /* + As we need file size for progression information and both copy method + call fstat (better than stat as it avoid race condition). + */ + if (fstat(in, &buf) < 0) + goto on_error; + + md = buf.st_mode; +#endif + + /* open write */ + out = open(copy->dest, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR); + if (out < 0) + goto on_error; + +#ifdef HAVE_SPLICE + /* fast file copy code using Linux splice API */ + result = _eio_file_copy_splice(thread, copy, in, out, buf.st_size); + if (result == 0) + goto on_error; +#endif + + /* classic copy method using mmap and write */ + if (result == -1) + { +#ifndef HAVE_SPLICE + struct stat buf; + + if (stat(copy->source, &buf) < 0) + goto on_error; + + md = buf.st_mode; +#endif + + f = eina_file_open(copy->source, 0); + if (!f) goto on_error; + + if (!_eio_file_copy_mmap(thread, copy, f, out)) + { + eina_file_close(f); + goto on_error; + } + + _eio_eina_file_copy_xattr(thread, copy, f, out); + + eina_file_close(f); + } + else + { +#if defined HAVE_XATTR && defined HAVE_SPLICE + _eio_file_copy_xattr(thread, copy, in, out); +#endif + } + + /* change access right to match source */ +#ifdef HAVE_CHMOD + if (fchmod(out, md) != 0) + goto on_error; +#else + if (chmod(copy->dest, md) != 0) + goto on_error; +#endif + + close(out); +#ifdef HAVE_SPLICE + close(in); +#endif + + return EINA_TRUE; + + on_error: + eio_file_thread_error(©->common, thread); + +#ifdef HAVE_SPLICE + if (in >= 0) close(in); +#endif + if (out >= 0) close(out); + if (out >= 0) + unlink(copy->dest); + return EINA_FALSE; +} + +void +eio_async_free(Eio_File_Ls *async) +{ + eina_stringshare_del(async->directory); + eio_file_free(&async->common); +} + +void +eio_async_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Ls *async = data; + + async->common.done_cb((void*) async->common.data, &async->common); + + eio_async_free(async); +} + +void +eio_async_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Ls *async = data; + + eio_file_error(&async->common); + + eio_async_free(async); +} + +/** + * @endcond + */ + + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI Eio_File * +eio_file_ls(const char *dir, + Eio_Filter_Cb filter_cb, + Eio_Main_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Char_Ls *async; + + EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + async = malloc(sizeof (Eio_File_Char_Ls)); + EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL); + + async->filter_cb = filter_cb; + async->main_cb = main_cb; + async->ls.directory = eina_stringshare_add(dir); + + if (!eio_long_file_set(&async->ls.common, + done_cb, + error_cb, + data, + _eio_file_heavy, + _eio_file_notify, + eio_async_end, + eio_async_error)) + return NULL; + + return &async->ls.common; +} + +EAPI Eio_File * +eio_file_direct_ls(const char *dir, + Eio_Filter_Direct_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Direct_Ls *async; + + EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + async = malloc(sizeof(Eio_File_Direct_Ls)); + EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL); + + async->filter_cb = filter_cb; + async->main_cb = main_cb; + async->ls.directory = eina_stringshare_add(dir); + + if (!eio_long_file_set(&async->ls.common, + done_cb, + error_cb, + data, + _eio_file_direct_heavy, + _eio_file_direct_notify, + eio_async_end, + eio_async_error)) + return NULL; + + return &async->ls.common; +} + +EAPI Eio_File * +eio_file_stat_ls(const char *dir, + Eio_Filter_Direct_Cb filter_cb, + Eio_Main_Direct_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Direct_Ls *async; + + EINA_SAFETY_ON_NULL_RETURN_VAL(dir, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + async = malloc(sizeof(Eio_File_Direct_Ls)); + EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL); + + async->filter_cb = filter_cb; + async->main_cb = main_cb; + async->ls.directory = eina_stringshare_add(dir); + + if (!eio_long_file_set(&async->ls.common, + done_cb, + error_cb, + data, + _eio_file_stat_heavy, + _eio_file_direct_notify, + eio_async_end, + eio_async_error)) + return NULL; + + return &async->ls.common; +} + +EAPI Eina_Bool +eio_file_cancel(Eio_File *ls) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ls, EINA_FALSE); + return ecore_thread_cancel(ls->thread); +} + +EAPI Eina_Bool +eio_file_check(Eio_File *ls) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ls, EINA_TRUE); + return ecore_thread_check(ls->thread); +} + +EAPI void * +eio_file_container_get(Eio_File *ls) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ls, EINA_FALSE); + return ls->container; } EAPI Eina_Bool -eio_file_cancel(Eio_List *list) +eio_file_associate_add(Eio_File *ls, + const char *key, + const void *data, Eina_Free_Cb free_cb) { - return ecore_thread_cancel(list->thread); + /* FIXME: Check if we are in the right worker thred */ + if (!ls->worker.associated) + ls->worker.associated = eina_hash_string_small_new(eio_associate_free); + + return eina_hash_add(ls->worker.associated, + key, + eio_associate_malloc(data, free_cb)); } +EAPI Eina_Bool +eio_file_associate_direct_add(Eio_File *ls, + const char *key, + const void *data, Eina_Free_Cb free_cb) +{ + /* FIXME: Check if we are in the right worker thred */ + if (!ls->worker.associated) + ls->worker.associated = eina_hash_string_small_new(eio_associate_free); + + return eina_hash_direct_add(ls->worker.associated, + key, + eio_associate_malloc(data, free_cb)); +} + +EAPI void * +eio_file_associate_find(Eio_File *ls, const char *key) +{ + Eio_File_Associate *search; + if (!ls->main.associated) + return NULL; + + search = eina_hash_find(ls->main.associated, key); + if (!search) return NULL; + return search->data; +} + +EAPI Eio_File * +eio_file_copy(const char *source, + const char *dest, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Progress *copy; + + EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + copy = malloc(sizeof(Eio_File_Progress)); + EINA_SAFETY_ON_NULL_RETURN_VAL(copy, NULL); + + copy->op = EIO_FILE_COPY; + copy->progress_cb = progress_cb; + copy->source = eina_stringshare_add(source); + copy->dest = eina_stringshare_add(dest); + + if (!eio_long_file_set(©->common, + done_cb, + error_cb, + data, + _eio_file_copy_heavy, + _eio_file_copy_notify, + _eio_file_copy_end, + _eio_file_copy_error)) + return NULL; + + return ©->common; +} + +EAPI Eio_File * +eio_file_move(const char *source, + const char *dest, + Eio_Progress_Cb progress_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Move *move; + + EINA_SAFETY_ON_NULL_RETURN_VAL(source, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(dest, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + move = malloc(sizeof(Eio_File_Move)); + EINA_SAFETY_ON_NULL_RETURN_VAL(move, NULL); + + move->progress.op = EIO_FILE_MOVE; + move->progress.progress_cb = progress_cb; + move->progress.source = eina_stringshare_add(source); + move->progress.dest = eina_stringshare_add(dest); + move->copy = NULL; + + if (!eio_long_file_set(&move->progress.common, + done_cb, + error_cb, + data, + _eio_file_move_heavy, + _eio_file_move_notify, + _eio_file_move_end, + _eio_file_move_error)) + return NULL; + + return &move->progress.common; +} diff --git a/src/lib/eio_inline_helper.x b/src/lib/eio_inline_helper.x new file mode 100644 index 0000000..af49646 --- /dev/null +++ b/src/lib/eio_inline_helper.x @@ -0,0 +1,105 @@ +/* EIO - EFL data type library + * Copyright (C) 2010 Enlightenment Developers: + * Cedric Bail + * Vincent "caro" Torri + * Stephen "okra" Houston + * + * 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 . + */ + +#ifndef EIO_INLINE_HELPER_H__ +# define EIO_INLINE_HELPER_H__ + +/** + * @addtogroup Eio_Helper + * + * @{ + */ + +/** + * @brief Return last acces time to a file + * @param stat The stat buffer as given by eio_file_stat callback. + * @return last access time. + * + * This function return the st_atime field, last acces time, as double like all EFL time call. + */ +static inline double +eio_file_atime(const Eina_Stat *st) +{ + if (!st) return 0.0; + return (double) st->atime; +} + +/** + * @brief Return last modification time of a file + * @param stat The stat buffer as given by eio_file_stat callback. + * @return last modification time. + * + * This function return the st_mtime field, last modification time, as double like all EFL time call. + */ +static inline double +eio_file_mtime(const Eina_Stat *st) +{ + if (!st) return 0.0; + return (double) st->mtime; +} + +/** + * @brief Return file length. + * @param stat The stat buffer as given by eio_file_stat callback. + * @return the length of a file. + * + * This function is just an accessor to st_size and return the file length. + */ +static inline long long +eio_file_size(const Eina_Stat *st) +{ + if (!st) return 0; + return st->size; +} + +/** + * @brief Return if path is a directory. + * @param stat The stat buffer as given by eio_file_stat callback. + * @return EINA_TRUE if the path is a directory. + * + * This function tell you if the stated path is a directory or not. + */ +static inline Eina_Bool +eio_file_is_dir(const Eina_Stat *st) +{ + if (!st) return EINA_FALSE; + return (S_ISDIR(st->mode)) ? EINA_TRUE : EINA_FALSE; +} + +/** + * @brief Return if path is a length. + * @param stat The stat buffer as given by eio_file_stat callback. + * @return EINA_TRUE if the path is a length. + * + * This function tell you if the stated path is a length or not. + */ +static inline Eina_Bool +eio_file_is_lnk(const Eina_Stat *st) +{ + if (!st) return EINA_FALSE; + return (S_ISLNK(st->mode)) ? EINA_TRUE : EINA_FALSE; +} + +/** + * @} + */ + +#endif diff --git a/src/lib/eio_main.c b/src/lib/eio_main.c new file mode 100644 index 0000000..e65f75b --- /dev/null +++ b/src/lib/eio_main.c @@ -0,0 +1,300 @@ +/* EIO - EFL data type library + * Copyright (C) 2010 Enlightenment Developers: + * 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 . + */ +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +static Eio_Version _version = { VMAJ, VMIN, VMIC, VREV }; +EAPI Eio_Version *eio_version = &_version; + +/** + * @cond LOCAL + */ + +#ifdef EFL_HAVE_POSIX_THREADS +# define EIO_MUTEX_TYPE pthread_mutex_t +# define EIO_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER +# define EIO_MUTEX_INIT(Pool) +# define EIO_MUTEX_LOCK(Pool) pthread_mutex_lock(&Pool->lock) +# define EIO_MUTEX_UNLOCK(Pool) pthread_mutex_unlock(&Pool->lock) +# define EIO_MUTEX_DESTROY(Pool) +#endif + +#ifdef EFL_HAVE_WIN32_THREADS +# define EIO_MUTEX_TYPE HANDLE +# define EIO_MUTEX_INITIALIZER NULL +# define EIO_MUTEX_INIT(Pool) Pool.lock = CreateMutex(NULL, FALSE, NULL) +# define EIO_MUTEX_LOCK(Pool) WaitForSingleObject(Pool->lock, INFINITE) +# define EIO_MUTEX_UNLOCK(Pool) ReleaseMutex(Pool->lock) +# define EIO_MUTEX_DESTROY(Pool) CloseHandle(Pool.lock) +#endif + +/* Progress pool */ +typedef struct _Eio_Alloc_Pool Eio_Alloc_Pool; + +struct _Eio_Alloc_Pool +{ + int count; + Eina_Trash *trash; + + EIO_MUTEX_TYPE lock; +}; + +static int _eio_init_count = 0; +int _eio_log_dom_global = -1; + +static Eio_Alloc_Pool progress_pool = { 0, NULL, EIO_MUTEX_INITIALIZER }; +static Eio_Alloc_Pool direct_info_pool = { 0, NULL, EIO_MUTEX_INITIALIZER }; +static Eio_Alloc_Pool char_pool = { 0, NULL, EIO_MUTEX_INITIALIZER }; +static Eio_Alloc_Pool associate_pool = { 0, NULL, EIO_MUTEX_INITIALIZER }; + +static void * +_eio_pool_malloc(Eio_Alloc_Pool *pool, size_t sz) +{ + void *result = NULL; + + if (pool->count) + { + EIO_MUTEX_LOCK(pool); + result = eina_trash_pop(&pool->trash); + if (result) pool->count--; + EIO_MUTEX_UNLOCK(pool); + } + + if (!result) result = malloc(sz); + return result; +} + +static void +_eio_pool_free(Eio_Alloc_Pool *pool, void *data) +{ + if (pool->count >= EIO_PROGRESS_LIMIT) + { + free(data); + } + else + { + EIO_MUTEX_LOCK(pool); + eina_trash_push(&pool->trash, data); + pool->count++; + EIO_MUTEX_UNLOCK(pool); + } +} + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +Eio_Progress * +eio_progress_malloc(void) +{ + return _eio_pool_malloc(&progress_pool, sizeof (Eio_Progress)); +} + +void +eio_progress_free(Eio_Progress *data) +{ + eina_stringshare_del(data->source); + eina_stringshare_del(data->dest); + + _eio_pool_free(&progress_pool, data); +} + +void +eio_progress_send(Ecore_Thread *thread, Eio_File_Progress *op, long long current, long long max) +{ + Eio_Progress *progress; + + if (op->progress_cb == NULL) + return ; + + progress = eio_progress_malloc(); + if (!progress) return ; + + progress->op = op->op; + progress->current = current; + progress->max = max; + progress->percent = (float) current * 100.0 / (float) max; + progress->source = eina_stringshare_ref(op->source); + progress->dest = eina_stringshare_ref(op->dest); + + ecore_thread_feedback(thread, progress); +} + +Eio_File_Direct_Info * +eio_direct_info_malloc(void) +{ + return _eio_pool_malloc(&direct_info_pool, sizeof (Eio_File_Direct_Info)); +} + +void +eio_direct_info_free(Eio_File_Direct_Info *data) +{ + _eio_pool_free(&direct_info_pool, data); +} + +Eio_File_Char * +eio_char_malloc(void) +{ + return _eio_pool_malloc(&char_pool, sizeof (Eio_File_Char)); +} + +void +eio_char_free(Eio_File_Char *data) +{ + _eio_pool_free(&char_pool, data); +} + +Eio_File_Associate * +eio_associate_malloc(const void *data, Eina_Free_Cb free_cb) +{ + Eio_File_Associate *tmp; + + tmp = _eio_pool_malloc(&associate_pool, sizeof (Eio_File_Associate)); + if (!tmp) return tmp; + + tmp->data = (void*) data; + tmp->free_cb = free_cb; + + return tmp; +} + +void +eio_associate_free(void *data) +{ + Eio_File_Associate *tmp; + + if (!data) return ; + + tmp = data; + if (tmp->free_cb) + tmp->free_cb(tmp->data); + _eio_pool_free(&associate_pool, tmp); +} + + +/** + * @endcond + */ + + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI int +eio_init(void) +{ + if (++_eio_init_count != 1) + return _eio_init_count; + + if (!eina_init()) + { + fprintf(stderr, "Eio can not initialize Eina\n"); + return --_eio_init_count; + } + + _eio_log_dom_global = eina_log_domain_register("eio", EIO_DEFAULT_LOG_COLOR); + if (_eio_log_dom_global < 0) + { + EINA_LOG_ERR("Eio can not create a general log domain."); + goto shutdown_eina; + } + + if (!ecore_init()) + { + ERR("Can not initialize Eina\n"); + goto unregister_log_domain; + } + + EIO_MUTEX_INIT(progress_pool); + EIO_MUTEX_INIT(direct_info_pool); + EIO_MUTEX_INIT(char_pool); + EIO_MUTEX_INIT(associate_pool); + + eio_monitor_init(); + + return _eio_init_count; + +unregister_log_domain: + eina_log_domain_unregister(_eio_log_dom_global); + _eio_log_dom_global = -1; +shutdown_eina: + eina_shutdown(); + return --_eio_init_count; +} + +EAPI int +eio_shutdown(void) +{ + Eio_File_Direct_Info *info; + Eio_File_Char *cin; + Eio_Progress *pg; + Eio_File_Associate *asso; + + if (_eio_init_count <= 0) + { + ERR("Init count not greater than 0 in shutdown."); + return 0; + } + if (--_eio_init_count != 0) + return _eio_init_count; + + eio_monitor_shutdown(); + + EIO_MUTEX_DESTROY(direct_info_pool); + EIO_MUTEX_DESTROY(progress_pool); + EIO_MUTEX_DESTROY(char_pool); + EIO_MUTEX_DESTROY(associate_pool); + + /* Cleanup pool */ + EINA_TRASH_CLEAN(&progress_pool.trash, pg) + free(pg); + progress_pool.count = 0; + + EINA_TRASH_CLEAN(&direct_info_pool.trash, info) + free(info); + direct_info_pool.count = 0; + + EINA_TRASH_CLEAN(&char_pool.trash, cin) + free(cin); + char_pool.count = 0; + + EINA_TRASH_CLEAN(&associate_pool.trash, asso) + free(asso); + associate_pool.count = 0; + + ecore_shutdown(); + eina_log_domain_unregister(_eio_log_dom_global); + _eio_log_dom_global = -1; + eina_shutdown(); + + return _eio_init_count; +} diff --git a/src/lib/eio_map.c b/src/lib/eio_map.c new file mode 100644 index 0000000..9edc0ad --- /dev/null +++ b/src/lib/eio_map.c @@ -0,0 +1,316 @@ +/* EIO - EFL data type library + * Copyright (C) 2010 Enlightenment Developers: + * Cedric Bail + * Vincent "caro" Torri + * Stephen "okra" Houston + * + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +static void +_eio_file_open_job(void *data, Ecore_Thread *thread) +{ + Eio_File_Map *map = data; + + map->result = eina_file_open(map->name, map->shared); + if (!map->result) eio_file_thread_error(&map->common, thread); +} + +static void +_eio_file_open_free(Eio_File_Map *map) +{ + if (map->name) eina_stringshare_del(map->name); + free(map); +} + +static void +_eio_file_open_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Map *map = data; + + map->open_cb((void*) map->common.data, &map->common, map->result); + _eio_file_open_free(map); +} + +static void +_eio_file_open_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Map *map = data; + + eio_file_error(&map->common); + _eio_file_open_free(map); +} + +static void +_eio_file_close_job(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Map *map = data; + + eina_file_close(map->result); +} + +static void +_eio_file_close_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Map *map = data; + + map->common.done_cb((void*) map->common.data, &map->common); + _eio_file_open_free(map); +} + +static void +_eio_file_close_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Map *map = data; + + eio_file_error(&map->common); + _eio_file_open_free(map); +} + +static void +_eio_file_map_all_job(void *data, Ecore_Thread *thread) +{ + Eio_File_Map_Rule *map = data; + + eio_file_container_set(&map->common, map->file); + map->result = eina_file_map_all(map->common.container, map->rule); + if (map->result && map->filter_cb) + { + if (!map->filter_cb((void*) map->common.data, + &map->common, + map->result, + map->length)) + { + eina_file_map_free(map->common.container, map->result); + map->result = NULL; + } + } + + if (!map->result) + eio_file_thread_error(&map->common, thread); +} + +static void +_eio_file_map_new_job(void *data, Ecore_Thread *thread) +{ + Eio_File_Map_Rule *map = data; + + eio_file_container_set(&map->common, map->file); + map->result = eina_file_map_new(map->common.container, map->rule, + map->offset, map->length); + if (map->result && map->filter_cb) + { + if (!map->filter_cb((void*) map->common.data, + &map->common, + map->result, + map->length)) + { + eina_file_map_free(map->common.container, map->result); + map->result = NULL; + } + } + + if (!map->result) + eio_file_thread_error(&map->common, thread); +} + +static void +_eio_file_map_end(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Map_Rule *map = data; + + map->map_cb((void*) map->common.data, &map->common, map->result, map->length); + free(map); +} + +static void +_eio_file_map_cancel(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Map_Rule *map = data; + + eio_file_error(&map->common); + free(map); +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + + +/** + * @endcond + */ + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI Eio_File * +eio_file_open(const char *name, Eina_Bool shared, + Eio_Open_Cb open_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Map *map; + + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(open_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + map = malloc(sizeof (Eio_File_Map)); + EINA_SAFETY_ON_NULL_RETURN_VAL(map, NULL); + + map->open_cb = open_cb; + map->name = eina_stringshare_add(name); + map->shared = shared; + map->result = NULL; + + if (!eio_file_set(&map->common, + NULL, + error_cb, + data, + _eio_file_open_job, + _eio_file_open_end, + _eio_file_open_cancel)) + return NULL; + + return &map->common; +} + +EAPI Eio_File * +eio_file_close(Eina_File *f, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Map *map; + + EINA_SAFETY_ON_NULL_RETURN_VAL(f, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + map = malloc(sizeof (Eio_File_Map)); + EINA_SAFETY_ON_NULL_RETURN_VAL(map, NULL); + + map->name = NULL; + map->result = f; + + if (!eio_file_set(&map->common, + done_cb, + error_cb, + data, + _eio_file_close_job, + _eio_file_close_end, + _eio_file_close_cancel)) + return NULL; + + return &map->common; +} + +EAPI Eio_File * +eio_file_map_all(Eina_File *f, + Eina_File_Populate rule, + Eio_Filter_Map_Cb filter_cb, + Eio_Map_Cb map_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Map_Rule *map; + + EINA_SAFETY_ON_NULL_RETURN_VAL(f, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(map_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + map = malloc(sizeof (Eio_File_Map_Rule)); + EINA_SAFETY_ON_NULL_RETURN_VAL(map, NULL); + + map->file = f; + map->filter_cb = filter_cb; + map->map_cb = map_cb; + map->rule = rule; + map->result = NULL; + map->length = eina_file_size_get(f); + + if (!eio_file_set(&map->common, + NULL, + error_cb, + data, + _eio_file_map_all_job, + _eio_file_map_end, + _eio_file_map_cancel)) + return NULL; + + return &map->common; +} + +EAPI Eio_File * +eio_file_map_new(Eina_File *f, + Eina_File_Populate rule, + unsigned long int offset, + unsigned long int length, + Eio_Filter_Map_Cb filter_cb, + Eio_Map_Cb map_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Map_Rule *map; + + EINA_SAFETY_ON_NULL_RETURN_VAL(f, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(map_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + map = malloc(sizeof (Eio_File_Map_Rule)); + EINA_SAFETY_ON_NULL_RETURN_VAL(map, NULL); + + map->common.container = f; + map->filter_cb = filter_cb; + map->map_cb = map_cb; + map->rule = rule; + map->result = NULL; + map->offset = offset; + map->length = length; + + if (!eio_file_set(&map->common, + NULL, + error_cb, + data, + _eio_file_map_new_job, + _eio_file_map_end, + _eio_file_map_cancel)) + return NULL; + + return &map->common; +} diff --git a/src/lib/eio_monitor.c b/src/lib/eio_monitor.c new file mode 100644 index 0000000..9f735d6 --- /dev/null +++ b/src/lib/eio_monitor.c @@ -0,0 +1,351 @@ +/* EIO - EFL data type library + * Copyright (C) 2011 Enlightenment Developers: + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +static Eina_Hash *_eio_monitors = NULL; +static pid_t _monitor_pid = -1; + +static void +_eio_monitor_free(Eio_Monitor *monitor) +{ + if (!monitor->delete_me) + eina_hash_del(_eio_monitors, monitor->path, monitor); + + if (monitor->exist) eio_file_cancel(monitor->exist); + + if (monitor->backend) + { + if (!monitor->fallback) + eio_monitor_backend_del(monitor); + else + eio_monitor_fallback_del(monitor); + } + + eina_stringshare_del(monitor->path); + free(monitor); +} + +static void +_eio_monitor_error_cleanup_cb(__UNUSED__ void *user_data, void *func_data) +{ + Eio_Monitor_Error *ev = func_data; + + EINA_REFCOUNT_UNREF(ev->monitor) + _eio_monitor_free(ev->monitor); + free(ev); +} + +static void +_eio_monitor_event_cleanup_cb(__UNUSED__ void *user_data, void *func_data) +{ + Eio_Monitor_Event *ev = func_data; + + EINA_REFCOUNT_UNREF(ev->monitor) + _eio_monitor_free(ev->monitor); + eina_stringshare_del(ev->filename); + free(ev); +} + +static void +_eio_monitor_stat_cb(void *data, __UNUSED__ Eio_File *handler, __UNUSED__ const Eina_Stat *st) +{ + Eio_Monitor *monitor = data; + + monitor->exist = NULL; + + if (EINA_REFCOUNT_GET(monitor) > 1) + eio_monitor_backend_add(monitor); + + EINA_REFCOUNT_UNREF(monitor) + _eio_monitor_free(monitor); +} + +static void +_eio_monitor_error(Eio_Monitor *monitor, int error) +{ + Eio_Monitor_Error *ev; + + ev = calloc(1, sizeof (Eio_Monitor_Error)); + if (!ev) return ; + + ev->monitor = monitor; + EINA_REFCOUNT_REF(ev->monitor); + ev->error = error; + + ecore_event_add(EIO_MONITOR_ERROR, ev, _eio_monitor_error_cleanup_cb, NULL); +} + +static void +_eio_monitor_error_cb(void *data, Eio_File *handler __UNUSED__, int error) +{ + Eio_Monitor *monitor = data; + + monitor->error = error; + monitor->exist = NULL; + + if (EINA_REFCOUNT_GET(monitor) >= 1) + _eio_monitor_error(monitor, error); + + EINA_REFCOUNT_UNREF(monitor) + _eio_monitor_free(monitor); + + return ; +} + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +void +eio_monitor_init(void) +{ + EIO_MONITOR_ERROR = ecore_event_type_new(); + EIO_MONITOR_SELF_RENAME = ecore_event_type_new(); + EIO_MONITOR_SELF_DELETED = ecore_event_type_new(); + EIO_MONITOR_FILE_CREATED = ecore_event_type_new(); + EIO_MONITOR_FILE_DELETED = ecore_event_type_new(); + EIO_MONITOR_FILE_MODIFIED = ecore_event_type_new(); + EIO_MONITOR_FILE_CLOSED = ecore_event_type_new(); + EIO_MONITOR_DIRECTORY_CREATED = ecore_event_type_new(); + EIO_MONITOR_DIRECTORY_DELETED = ecore_event_type_new(); + EIO_MONITOR_DIRECTORY_MODIFIED = ecore_event_type_new(); + EIO_MONITOR_DIRECTORY_CLOSED = ecore_event_type_new(); + + eio_monitor_backend_init(); + eio_monitor_fallback_init(); + + _eio_monitors = eina_hash_stringshared_new(NULL); + /* FIXME: this check is optional, but if it is kept then failure should be handled more gracefully */ + if (!_eio_monitors) abort(); + + _monitor_pid = getpid(); +} + +void +eio_monitor_shutdown(void) +{ + Eina_Iterator *it; + Eio_Monitor *monitor; + + it = eina_hash_iterator_data_new(_eio_monitors); + EINA_ITERATOR_FOREACH(it, monitor) + { + if (monitor->exist) + { + eio_file_cancel(monitor->exist); + monitor->exist = NULL; + } + monitor->delete_me = EINA_TRUE; + } + eina_iterator_free(it); + eina_hash_free(_eio_monitors); + + eio_monitor_backend_shutdown(); + eio_monitor_fallback_shutdown(); + + _monitor_pid = -1; +} + +void +_eio_monitor_send(Eio_Monitor *monitor, const char *filename, int event_code) +{ + Eio_Monitor_Event *ev; + + ev = calloc(1, sizeof (Eio_Monitor_Event)); + if (!ev) return ; + + ev->monitor = monitor; + EINA_REFCOUNT_REF(ev->monitor); + ev->filename = eina_stringshare_add(filename); + + ecore_event_add(event_code, ev, _eio_monitor_event_cleanup_cb, NULL); +} + +void +_eio_monitor_rename(Eio_Monitor *monitor, const char *newpath) +{ + const char *tmp; + + /* destroy old state */ + if (monitor->exist) eio_file_cancel(monitor->exist); + + if (monitor->backend) + { + if (!monitor->fallback) + eio_monitor_backend_del(monitor); + else + eio_monitor_fallback_del(monitor); + } + + /* rename */ + tmp = monitor->path; + monitor->path = eina_stringshare_add(newpath); + eina_hash_move(_eio_monitors, tmp, monitor->path); + eina_stringshare_del(tmp); + + /* That means death (cmp pointer and not content) */ + if (tmp == monitor->path) + { + _eio_monitor_error(monitor, -1); + return ; + } + + EINA_REFCOUNT_REF(monitor); /* as we spawn a thread for this monitor, we need to refcount specifically for it */ + + /* restart */ + monitor->rename = EINA_TRUE; + monitor->exist = eio_file_direct_stat(monitor->path, + _eio_monitor_stat_cb, + _eio_monitor_error_cb, + monitor); + + /* FIXME: probably should handle this more gracefully */ + if (!monitor->exist) abort(); + /* and notify the app */ + _eio_monitor_send(monitor, newpath, EIO_MONITOR_SELF_RENAME); +} + +/** + * @endcond + */ + + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI int EIO_MONITOR_ERROR; +EAPI int EIO_MONITOR_FILE_CREATED; +EAPI int EIO_MONITOR_FILE_DELETED; +EAPI int EIO_MONITOR_FILE_MODIFIED; +EAPI int EIO_MONITOR_FILE_CLOSED; +EAPI int EIO_MONITOR_DIRECTORY_CREATED; +EAPI int EIO_MONITOR_DIRECTORY_DELETED; +EAPI int EIO_MONITOR_DIRECTORY_MODIFIED; +EAPI int EIO_MONITOR_DIRECTORY_CLOSED; +EAPI int EIO_MONITOR_SELF_RENAME; +EAPI int EIO_MONITOR_SELF_DELETED; + +EAPI Eio_Monitor * +eio_monitor_add(const char *path) +{ + const char *tmp; + Eio_Monitor *ret; + + tmp = eina_stringshare_add(path); + ret = eio_monitor_stringshared_add(tmp); + eina_stringshare_del(tmp); + return ret; +} + +EAPI Eio_Monitor * +eio_monitor_stringshared_add(const char *path) +{ + Eio_Monitor *monitor; + struct stat st; + + if (_monitor_pid == -1) return NULL; + + if (_monitor_pid != getpid()) + { + eio_monitor_shutdown(); + eio_monitor_init(); + } + + if (stat(path, &st) != 0) + { + INF("monitored path not found"); + return NULL; + } + + monitor = eina_hash_find(_eio_monitors, path); + + if (monitor) + { + if (st.st_mtime != monitor->mtime) + { + monitor->delete_me = EINA_TRUE; + eina_hash_del(_eio_monitors, monitor->path, monitor); + } + else + { + EINA_REFCOUNT_REF(monitor); + return monitor; + } + } + + monitor = malloc(sizeof (Eio_Monitor)); + if (!monitor) return NULL; + + monitor->mtime = st.st_mtime; + monitor->backend = NULL; // This is needed to avoid race condition + monitor->path = eina_stringshare_ref(path); + monitor->fallback = EINA_FALSE; + monitor->rename = EINA_FALSE; + monitor->delete_me = EINA_FALSE; + + EINA_REFCOUNT_INIT(monitor); + EINA_REFCOUNT_REF(monitor); /* as we spawn a thread for this monitor, we need to refcount specifically for it */ + + monitor->exist = eio_file_direct_stat(monitor->path, + _eio_monitor_stat_cb, + _eio_monitor_error_cb, + monitor); + if (!monitor->exist) + { + _eio_monitor_free(monitor); + return NULL; + } + + eina_hash_direct_add(_eio_monitors, path, monitor); + + return monitor; +} + +EAPI void +eio_monitor_del(Eio_Monitor *monitor) +{ + EINA_REFCOUNT_UNREF(monitor) + _eio_monitor_free(monitor); +} + +EAPI const char * +eio_monitor_path_get(Eio_Monitor *monitor) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(monitor, NULL); + return monitor->path; +} diff --git a/src/lib/eio_monitor_inotify.c b/src/lib/eio_monitor_inotify.c new file mode 100644 index 0000000..b5ffabd --- /dev/null +++ b/src/lib/eio_monitor_inotify.c @@ -0,0 +1,273 @@ +/* EIO - EFL data type library + * Copyright (C) 2011 Enlightenment Developers: + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + +#ifdef HAVE_SYS_INOTIFY +# include +#else +# include +# include +#endif + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +typedef struct _Eio_Inotify_Table Eio_Inotify_Table; + +struct _Eio_Inotify_Table +{ + int mask; + int *ev_file_code; + int *ev_dir_code; +}; + +struct _Eio_Monitor_Backend +{ + Eio_Monitor *parent; + + int hwnd; +}; + +static Ecore_Fd_Handler *_inotify_fdh = NULL; +static Eina_Hash *_inotify_monitors = NULL; + +#define EIO_INOTIFY_LINE(Ino, Ef, Ed) \ + { Ino, &EIO_MONITOR_##Ef, &EIO_MONITOR_##Ed } + +static const Eio_Inotify_Table match[] = { + EIO_INOTIFY_LINE(IN_ATTRIB, FILE_MODIFIED, DIRECTORY_MODIFIED), + EIO_INOTIFY_LINE(IN_CLOSE_WRITE, FILE_CLOSED, DIRECTORY_CLOSED), + EIO_INOTIFY_LINE(IN_MODIFY, FILE_MODIFIED, DIRECTORY_MODIFIED), + EIO_INOTIFY_LINE(IN_MOVED_FROM, FILE_DELETED, DIRECTORY_DELETED), + EIO_INOTIFY_LINE(IN_MOVED_TO, FILE_CREATED, DIRECTORY_CREATED), + EIO_INOTIFY_LINE(IN_DELETE, FILE_DELETED, DIRECTORY_DELETED), + EIO_INOTIFY_LINE(IN_CREATE, FILE_CREATED, DIRECTORY_CREATED), + EIO_INOTIFY_LINE(IN_DELETE_SELF, SELF_DELETED, SELF_DELETED), + EIO_INOTIFY_LINE(IN_MOVE_SELF, SELF_DELETED, SELF_DELETED), + EIO_INOTIFY_LINE(IN_UNMOUNT, SELF_DELETED, SELF_DELETED) +}; + +#ifndef HAVE_SYS_INOTIFY +static inline int +inotify_init(void) +{ + return syscall(__NR_inotify_init); +} + +static inline int +inotify_add_watch(int fd, const char *name, __u32 mask) +{ + return syscall(__NR_inotify_add_watch, fd, name, mask); +} + +static inline int +inotify_rm_watch(int fd, __u32 wd) +{ + return syscall(__NR_inotify_rm_watch, fd, wd); +} +#endif + +static void +_eio_inotify_del(void *data) +{ + Eio_Monitor_Backend *emb = data; + int fd; + + if (emb->hwnd) + { + fd = ecore_main_fd_handler_fd_get(_inotify_fdh); + inotify_rm_watch(fd, emb->hwnd); + emb->hwnd = 0; + } + + free(emb); +} + +static void +_eio_inotify_events(Eio_Monitor_Backend *backend, const char *file, int mask) +{ + char *tmp; + unsigned int length; + unsigned int tmp_length; + unsigned int i; + Eina_Bool is_dir; + + length = file ? strlen(file) : 0; + tmp_length = eina_stringshare_strlen(backend->parent->path) + length + 2; + tmp = alloca(sizeof (char) * tmp_length); + + snprintf(tmp, tmp_length, length ? "%s/%s" : "%s", + backend->parent->path, file); + + is_dir = !!(mask & IN_ISDIR); + + for (i = 0; i < sizeof (match) / sizeof (Eio_Inotify_Table); ++i) + if (match[i].mask & mask) + { + _eio_monitor_send(backend->parent, tmp, is_dir ? *match[i].ev_dir_code : *match[i].ev_file_code); + } + + /* special case for IN_IGNORED */ + if (mask & IN_IGNORED) + { + _eio_monitor_rename(backend->parent, tmp); + } +} + +static Eina_Bool +_eio_inotify_handler(void *data __UNUSED__, Ecore_Fd_Handler *fdh) +{ + Eio_Monitor_Backend *backend; + unsigned char buffer[16384]; + struct inotify_event *event; + int i = 0; + int event_size; + ssize_t size; + + size = read(ecore_main_fd_handler_fd_get(fdh), buffer, sizeof(buffer)); + while (i < size) + { + event = (struct inotify_event *)&buffer[i]; + event_size = sizeof(struct inotify_event) + event->len; + i += event_size; + + backend = eina_hash_find(_inotify_monitors, &event->wd); + if (!backend) continue ; + if (!backend->parent) continue ; + + _eio_inotify_events(backend, (event->len ? event->name : NULL), event->mask); + } + + return ECORE_CALLBACK_RENEW; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +/** + * @endcond + */ + +void eio_monitor_backend_init(void) +{ + int fd; + + fd = inotify_init(); + if (fd < 0) + return ; + + _inotify_fdh = ecore_main_fd_handler_add(fd, ECORE_FD_READ, _eio_inotify_handler, NULL, NULL, NULL); + if (!_inotify_fdh) + { + close(fd); + return ; + } + + _inotify_monitors = eina_hash_int32_new(_eio_inotify_del); +} + +void eio_monitor_backend_shutdown(void) +{ + int fd; + + if (!_inotify_fdh) return ; + + eina_hash_free(_inotify_monitors); + + fd = ecore_main_fd_handler_fd_get(_inotify_fdh); + ecore_main_fd_handler_del(_inotify_fdh); + _inotify_fdh = NULL; + + close(fd); +} + +void eio_monitor_backend_add(Eio_Monitor *monitor) +{ + Eio_Monitor_Backend *backend; + int mask = + IN_ATTRIB | + IN_CLOSE_WRITE | + IN_MOVED_FROM | + IN_MOVED_TO | + IN_DELETE | + IN_CREATE | + IN_MODIFY | + IN_DELETE_SELF | + IN_MOVE_SELF | + IN_UNMOUNT; + + if (!_inotify_fdh) + { + eio_monitor_fallback_add(monitor); + return; + } + + backend = calloc(1, sizeof (Eio_Monitor_Backend)); + if (!backend) + { + eio_monitor_fallback_add(monitor); + return; + } + + backend->parent = monitor; + backend->hwnd = inotify_add_watch(ecore_main_fd_handler_fd_get(_inotify_fdh), monitor->path, mask); + if (!backend->hwnd) + { + eio_monitor_fallback_add(monitor); + free(backend); + return; + } + + monitor->backend = backend; + + eina_hash_direct_add(_inotify_monitors, &backend->hwnd, backend); +} + +void eio_monitor_backend_del(Eio_Monitor *monitor) +{ + if (!_inotify_fdh) + eio_monitor_fallback_del(monitor); + + if (!monitor->backend) return ; + + eina_hash_del(_inotify_monitors, &monitor->backend->hwnd, monitor->backend); + monitor->backend = NULL; +} + + +/*============================================================================* + * API * + *============================================================================*/ diff --git a/src/lib/eio_monitor_poll.c b/src/lib/eio_monitor_poll.c new file mode 100644 index 0000000..1f09a42 --- /dev/null +++ b/src/lib/eio_monitor_poll.c @@ -0,0 +1,354 @@ +/* EIO - EFL data type library + * Copyright (C) 2011 Enlightenment Developers: + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +typedef struct _Eio_Monitor_Stat Eio_Monitor_Stat; + +struct _Eio_Monitor_Stat +{ + Eina_Stat buffer; + int version; +}; + +struct _Eio_Monitor_Backend +{ + Eio_Monitor *parent; + + Eina_Stat self; + Eina_Hash *children; + + Ecore_Timer *timer; + Ecore_Idler *idler; + Ecore_Thread *work; + + int version; + + Eina_Bool delete_me : 1; + Eina_Bool initialised : 1; + Eina_Bool destroyed : 1; +}; + +static Eina_Bool _eio_monitor_fallback_timer_cb(void *data); + +static void +_eio_monitor_fallback_heavy_cb(void *data, Ecore_Thread *thread) +{ + Eio_Monitor_Backend *backend = data; + Eina_Iterator *it; + Eina_Stat *est; + Eina_File_Direct_Info *info; + _eio_stat_t st; + /* FIXME : copy ecore_file_monitor_poll here */ + + if (!backend->initialised) + est = &backend->self; + else + est = alloca(sizeof (Eina_Stat)); + + if (!backend->parent) + return ; + + if (_eio_stat(backend->parent->path, &st)) + { + if (backend->initialised && !backend->destroyed) + { + ecore_thread_main_loop_begin(); + _eio_monitor_send(backend->parent, backend->parent->path, EIO_MONITOR_SELF_DELETED); + ecore_thread_main_loop_end(); + backend->destroyed = EINA_TRUE; + } + return ; + } + + backend->destroyed = EINA_FALSE; + + est->dev = st.st_dev; + est->ino = st.st_ino; + est->mode = st.st_mode; + est->nlink = st.st_nlink; + est->uid = st.st_uid; + est->gid = st.st_gid; + est->rdev = st.st_rdev; + est->size = st.st_size; +#ifdef _WIN32 + est->blksize = 0; + est->blocks = 0; +#else + est->blksize = st.st_blksize; + est->blocks = st.st_blocks; +#endif + est->atime = st.st_atime; + est->mtime = st.st_mtime; + est->ctime = st.st_ctime; +#ifdef _STAT_VER_LINUX +# if (defined __USE_MISC && defined st_mtime) + est->atimensec = st.st_atim.tv_nsec; + est->mtimensec = st.st_mtim.tv_nsec; + est->ctimensec = st.st_ctim.tv_nsec; +# else + est->atimensec = st.st_atimensec; + est->mtimensec = st.st_mtimensec; + est->ctimensec = st.st_ctimensec; +# endif +#else + est->atimensec = 0; + est->mtimensec = 0; + est->ctimensec = 0; +#endif + + if (memcmp(est, &backend->self, sizeof (Eina_Stat)) != 0) + { + ecore_thread_main_loop_begin(); + _eio_monitor_send(backend->parent, backend->parent->path, EIO_MONITOR_SELF_DELETED); + ecore_thread_main_loop_end(); + } + + it = eina_file_direct_ls(backend->parent->path); + EINA_ITERATOR_FOREACH(it, info) + { + Eio_Monitor_Stat *cmp; + Eio_Monitor_Stat buffer; + + if (!backend->initialised) + cmp = calloc(1, sizeof (Eio_Monitor_Stat)); + else + cmp = &buffer; + + if (eina_file_statat(eina_iterator_container_get(it), info, &cmp->buffer)) + { + if (!backend->initialised) free(cmp); + continue ; + } + + if (!backend->initialised) + { + eina_hash_add(backend->children, info->path + info->name_start, cmp); + } + else + { + cmp = eina_hash_find(backend->children, info->path + info->name_start); + if (!cmp) + { + /* New file or new directory added */ + ecore_thread_main_loop_begin(); + _eio_monitor_send(backend->parent, info->path + info->name_start, + info->type != EINA_FILE_DIR ? EIO_MONITOR_FILE_CREATED : EIO_MONITOR_DIRECTORY_CREATED); + ecore_thread_main_loop_end(); + + cmp = malloc(sizeof (Eio_Monitor_Stat)); + memcpy(cmp, &buffer, sizeof (Eina_Stat)); + + eina_hash_add(backend->children, info->path + info->name_start, cmp); + } + else if (memcmp(cmp, &buffer, sizeof (Eina_Stat)) != 0) + { + /* file has been modified */ + ecore_thread_main_loop_begin(); + _eio_monitor_send(backend->parent, info->path + info->name_start, + info->type != EINA_FILE_DIR ? EIO_MONITOR_FILE_MODIFIED : EIO_MONITOR_DIRECTORY_MODIFIED); + ecore_thread_main_loop_end(); + + memcpy(cmp, &buffer, sizeof (Eina_Stat)); + } + } + + cmp->version = backend->version; + if (ecore_thread_check(thread)) goto out; + } + out: + if (it) eina_iterator_free(it); + + if (backend->initialised && !ecore_thread_check(thread)) + { + Eina_Hash_Tuple *tuple; + + it = eina_hash_iterator_tuple_new(backend->children); + ecore_thread_main_loop_begin(); + + EINA_ITERATOR_FOREACH(it, tuple) + { + Eio_Monitor_Stat *cmp = tuple->data; + + if (cmp->version != backend->version) + { + _eio_monitor_send(backend->parent, tuple->key, + eio_file_is_dir(&cmp->buffer) ? EIO_MONITOR_DIRECTORY_DELETED : EIO_MONITOR_FILE_DELETED); + eina_hash_del(backend->children, tuple->key, tuple->data); + } + } + + ecore_thread_main_loop_end(); + eina_iterator_free(it); + } + + backend->version++; + backend->initialised = EINA_TRUE; +} + +static void +_eio_monitor_fallback_end_cb(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Monitor_Backend *backend = data; + + backend->work = NULL; + backend->timer = ecore_timer_add(60.0, _eio_monitor_fallback_timer_cb, backend); +} + +static void +_eio_monitor_fallback_cancel_cb(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_Monitor_Backend *backend = data; + + backend->work = NULL; + if (backend->delete_me) + { + free(backend); + return ; + } + backend->timer = ecore_timer_add(60.0, _eio_monitor_fallback_timer_cb, backend); +} + +static Eina_Bool +_eio_monitor_fallback_idler_cb(void *data) +{ + Eio_Monitor_Backend *backend = data; + + backend->idler = NULL; + backend->work = ecore_thread_run(_eio_monitor_fallback_heavy_cb, + _eio_monitor_fallback_end_cb, + _eio_monitor_fallback_cancel_cb, + backend); + return EINA_FALSE; +} + +static Eina_Bool +_eio_monitor_fallback_timer_cb(void *data) +{ + Eio_Monitor_Backend *backend = data; + + backend->timer = NULL; + backend->idler = ecore_idler_add(_eio_monitor_fallback_idler_cb, backend); + + return EINA_FALSE; +} + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +#if !defined HAVE_INOTIFY && !defined HAVE_NOTIFY_WIN32 +void eio_monitor_backend_init(void) +{ +} + +void eio_monitor_backend_shutdown(void) +{ +} + +void eio_monitor_backend_add(Eio_Monitor *monitor) +{ + eio_monitor_fallback_add(monitor); +} + +void eio_monitor_backend_del(Eio_Monitor *monitor) +{ + eio_monitor_fallback_del(monitor); +} +#endif + +void +eio_monitor_fallback_init(void) +{ +} + +void +eio_monitor_fallback_shutdown(void) +{ +} + +void +eio_monitor_fallback_add(Eio_Monitor *monitor) +{ + Eio_Monitor_Backend *backend; + + monitor->backend = NULL; + + backend = calloc(1, sizeof (Eio_Monitor_Backend)); + if (!backend) return ; + + backend->children = eina_hash_string_superfast_new(free); + backend->parent = monitor; + monitor->backend = backend; + backend->work = ecore_thread_run(_eio_monitor_fallback_heavy_cb, + _eio_monitor_fallback_end_cb, + _eio_monitor_fallback_cancel_cb, + backend); +} + +void +eio_monitor_fallback_del(Eio_Monitor *monitor) +{ + Eio_Monitor_Backend *backend; + + backend = monitor->backend; + monitor->backend = NULL; + + if (!backend) return ; + + backend->parent = NULL; + if (backend->timer) ecore_timer_del(backend->timer); + backend->timer = NULL; + if (backend->idler) ecore_idler_del(backend->idler); + backend->idler = NULL; + if (backend->work) + { + backend->delete_me = EINA_TRUE; + ecore_thread_cancel(backend->work); + return ; + } + eina_hash_free(backend->children); + free(backend); +} + +/** + * @endcond + */ + + +/*============================================================================* + * API * + *============================================================================*/ diff --git a/src/lib/eio_monitor_win32.c b/src/lib/eio_monitor_win32.c new file mode 100644 index 0000000..16dbaa7 --- /dev/null +++ b/src/lib/eio_monitor_win32.c @@ -0,0 +1,425 @@ +/* EIO - EFL data type library + * Copyright (C) 2011 Enlightenment Developers: + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +typedef struct _Eio_Monitor_Win32_Watcher Eio_Monitor_Win32_Watcher; + +/* 4096 = 256 * sizeof(FILE_NOTIFY_INFORMATION) */ +# define EIO_MONITOR_WIN32_BUFFER_SIZE 4096 + +struct _Eio_Monitor_Win32_Watcher +{ + char buffer[EIO_MONITOR_WIN32_BUFFER_SIZE]; + OVERLAPPED overlapped; + HANDLE handle; + HANDLE event; + Eio_Monitor *monitor; + Ecore_Win32_Handler *h; + char *current; + char *file; + DWORD buf_length; + Eina_Bool monitor_file : 1; + Eina_Bool monitor_parent : 1; +}; + +struct _Eio_Monitor_Backend +{ + Eio_Monitor *parent; + Eio_Monitor_Win32_Watcher *watcher_file; + Eio_Monitor_Win32_Watcher *watcher_dir; + Eio_Monitor_Win32_Watcher *watcher_parent; +}; + +static Eina_Bool _eio_monitor_win32_native = EINA_FALSE; + +static Eina_Bool +_eio_monitor_win32_cb(void *data, Ecore_Win32_Handler *wh __UNUSED__) +{ + PFILE_NOTIFY_INFORMATION fni; + Eio_Monitor_Win32_Watcher *w; + wchar_t *wname; + char *name; + DWORD filter; + DWORD offset; + DWORD buf_length; + int event; + + w = (Eio_Monitor_Win32_Watcher *)data; + + if (!GetOverlappedResult(w->handle, &w->overlapped, &buf_length, TRUE)) + return ECORE_CALLBACK_RENEW; + + fni = (PFILE_NOTIFY_INFORMATION)w->buffer; + do { + if (!fni) + break; + offset = fni->NextEntryOffset; + + wname = (wchar_t *)malloc(fni->FileNameLength + sizeof(wchar_t)); + if (!wname) + return 0; + + memcpy(wname, fni->FileName, fni->FileNameLength); + wname[fni->FileNameLength / sizeof(wchar_t)] = 0; + name = evil_wchar_to_char(wname); + free(wname); + if (!name) + return ECORE_CALLBACK_CANCEL; + + event = -1; + switch (fni->Action) + { + case FILE_ACTION_ADDED: + if (!w->monitor_parent) + { + if (w->monitor_file) + event = EIO_MONITOR_FILE_CREATED; + else + event = EIO_MONITOR_DIRECTORY_CREATED; + } + break; + case FILE_ACTION_REMOVED: + if (w->monitor_parent) + { + char path[MAX_PATH]; + char *res; + + res = _fullpath(path, name, MAX_PATH); + if (res && (strcmp(res, w->current) == 0)) + event = EIO_MONITOR_SELF_DELETED; + } + else + { + if (w->monitor_file) + event = EIO_MONITOR_FILE_DELETED; + else + event = EIO_MONITOR_DIRECTORY_DELETED; + } + break; + case FILE_ACTION_MODIFIED: + if (!w->monitor_parent) + { + if (w->monitor_file) + event = EIO_MONITOR_FILE_MODIFIED; + else + event = EIO_MONITOR_DIRECTORY_MODIFIED; + } + break; + case FILE_ACTION_RENAMED_OLD_NAME: + if (!w->monitor_parent) + { + if (w->monitor_file) + event = EIO_MONITOR_FILE_DELETED; + else + event = EIO_MONITOR_DIRECTORY_DELETED; + } + break; + case FILE_ACTION_RENAMED_NEW_NAME: + if (!w->monitor_parent) + { + if (w->monitor_file) + event = EIO_MONITOR_FILE_CREATED; + else + event = EIO_MONITOR_DIRECTORY_CREATED; + } + break; + default: + ERR("unknown event"); + event = EIO_MONITOR_ERROR; + break; + } + + if (event >= 0) + _eio_monitor_send(w->monitor, name, event); + + free(name); + + fni = (PFILE_NOTIFY_INFORMATION)((LPBYTE)fni + offset); + } while (offset); + + filter = + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY; + if (w->monitor_file) + filter |= FILE_NOTIFY_CHANGE_FILE_NAME; + else + filter |= FILE_NOTIFY_CHANGE_DIR_NAME; + + ReadDirectoryChangesW(w->handle, + (LPVOID)w->buffer, + EIO_MONITOR_WIN32_BUFFER_SIZE, + FALSE, + filter, + &w->buf_length, + &w->overlapped, + NULL); + + return ECORE_CALLBACK_RENEW; +} + +static Eio_Monitor_Win32_Watcher * +_eio_monitor_win32_watcher_new(Eio_Monitor *monitor, + char *current, + char *file, + Eina_Bool monitor_file, + Eina_Bool monitor_parent) +{ + Eio_Monitor_Win32_Watcher *w; + char *monitored; + DWORD filter; + + w = (Eio_Monitor_Win32_Watcher *)calloc(1, sizeof(Eio_Monitor_Win32_Watcher)); + if (!w) return NULL; + + if (!monitor_parent) + monitored = current; + else + { + char *tmp; + + tmp = strrchr(current, '\\'); + monitored = (char *)alloca((tmp - current) + 1); + memcpy(monitored, current, tmp - current); + monitored[tmp - current] = '\0'; + } + + w->handle = CreateFile(monitored, + FILE_LIST_DIRECTORY, + FILE_SHARE_READ | + FILE_SHARE_WRITE, + NULL, + OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | + FILE_FLAG_OVERLAPPED, + NULL); + if (w->handle == INVALID_HANDLE_VALUE) + goto free_w; + + w->event = CreateEvent(NULL, FALSE, FALSE, NULL); + if (!w->event) + goto close_handle; + + ZeroMemory (&w->overlapped, sizeof(w->overlapped)); + w->overlapped.hEvent = w->event; + + filter = + FILE_NOTIFY_CHANGE_ATTRIBUTES | + FILE_NOTIFY_CHANGE_SIZE | + FILE_NOTIFY_CHANGE_LAST_WRITE | + FILE_NOTIFY_CHANGE_LAST_ACCESS | + FILE_NOTIFY_CHANGE_CREATION | + FILE_NOTIFY_CHANGE_SECURITY; + if (monitor_file) + filter |= FILE_NOTIFY_CHANGE_FILE_NAME; + else + filter |= FILE_NOTIFY_CHANGE_DIR_NAME; + + if (!ReadDirectoryChangesW(w->handle, + (LPVOID)w->buffer, + EIO_MONITOR_WIN32_BUFFER_SIZE, + FALSE, + filter, + &w->buf_length, + &w->overlapped, + NULL)) + { + char *msg; + + msg = evil_last_error_get(); + if (msg) + { + ERR("%s", msg); + free(msg); + } + goto close_event; + } + + w->h = ecore_main_win32_handler_add(w->event, + _eio_monitor_win32_cb, + w); + if (!w->h) + goto close_event; + + w->monitor = monitor; + w->monitor_file = monitor_file; + w->monitor_parent = monitor_parent; + w->file = file; + w->current = current; + + return w; + + close_event: + CloseHandle(w->event); + close_handle: + CloseHandle(w->handle); + free_w: + free(w); + + return NULL; +} + +static void +_eio_monitor_win32_watcher_free(Eio_Monitor_Win32_Watcher *w) +{ + if (!w) return; + + if (w->file) + free(w->file); + free(w->current); + CloseHandle(w->event); + CloseHandle (w->handle); + free (w); +} + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +void eio_monitor_backend_init(void) +{ +} + +void eio_monitor_backend_shutdown(void) +{ +} + +void eio_monitor_backend_add(Eio_Monitor *monitor) +{ + char path[PATH_MAX]; + struct _stat s; + char *res; + char *current; + char *file = NULL; + Eio_Monitor_Backend *backend; + int ret; + + res = _fullpath(path, monitor->path, MAX_PATH); + if (!res) + goto fallback; + + ret = _stat(res, &s); + if (ret != 0) + goto fallback; + + if (_S_IFDIR & s.st_mode) + { + current = strdup(path); + if (!current) + goto fallback; + } + else if (_S_IFREG & s.st_mode) + { + char *tmp; + + tmp = strrchr(path, '\\'); + file = strdup(tmp + 1); + if (!file) + goto fallback; + + *tmp = '\0'; + current = strdup(path); + if (!current) + { + free(file); + goto fallback; + } + } + else + goto fallback; + + backend = calloc(1, sizeof (Eio_Monitor_Backend)); + if (!backend) + goto fallback; + + backend->parent = monitor; + + backend->watcher_file = _eio_monitor_win32_watcher_new(monitor, current, file, EINA_TRUE, EINA_FALSE); + if (!backend->watcher_file) + goto free_backend; + + backend->watcher_dir = _eio_monitor_win32_watcher_new(monitor, current, file, EINA_FALSE, EINA_FALSE); + if (!backend->watcher_dir) + goto free_backend_file; + + backend->watcher_parent = _eio_monitor_win32_watcher_new(monitor, current, file, EINA_FALSE, EINA_TRUE); + if (!backend->watcher_parent) + goto free_backend_dir; + + _eio_monitor_win32_native = EINA_TRUE; + monitor->backend = backend; + + return; + + free_backend_dir: + _eio_monitor_win32_watcher_free(backend->watcher_dir); + free_backend_file: + _eio_monitor_win32_watcher_free(backend->watcher_file); + free_backend: + free(backend); + fallback: + INF("falling back to poll monitoring"); + eio_monitor_fallback_add(monitor); +} + +void eio_monitor_backend_del(Eio_Monitor *monitor) +{ + if (!_eio_monitor_win32_native) + { + eio_monitor_fallback_del(monitor); + return ; + } + + _eio_monitor_win32_watcher_free(monitor->backend->watcher_parent); + _eio_monitor_win32_watcher_free(monitor->backend->watcher_dir); + _eio_monitor_win32_watcher_free(monitor->backend->watcher_file); + free(monitor->backend); + monitor->backend = NULL; +} + + +/** + * @endcond + */ + + +/*============================================================================* + * API * + *============================================================================*/ diff --git a/src/lib/eio_private.h b/src/lib/eio_private.h new file mode 100644 index 0000000..ef983f9 --- /dev/null +++ b/src/lib/eio_private.h @@ -0,0 +1,512 @@ +#ifndef EIO_PRIVATE_H_ +#define EIO_PRIVATE_H_ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#ifdef HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen ((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) ((dirent)->d_namlen) +# ifdef HAVE_SYS_NDIR_H +# include +# endif +# ifdef HAVE_SYS_DIR_H +# include +# endif +# ifdef HAVE_NDIR_H +# include +# endif +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_PWD_H +# include +#endif + +#ifdef HAVE_FEATURES_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_LIBGEN_H +# include +#endif + +#ifdef HAVE_GRP_H +# include +#endif + +#ifdef EFL_HAVE_POSIX_THREADS +# include +#endif + +#ifdef EFL_HAVE_WIN32_THREADS +# ifndef WIN32_LEAN_AND_MEAN +# define WIN32_LEAN_AND_MEAN +# endif +# include +# undef WIN32_LEAN_AND_MEAN +#endif + +#ifdef HAVE_EVIL +# include +#endif + +#include + +#include "Eio.h" + +#ifdef _WIN32 +typedef struct __stat64 _eio_stat_t; +#define _eio_stat(p, b) _stat64(p, b) +#define _eio_lstat(p, b) _stat64(p, b) +#else +typedef struct stat _eio_stat_t; +#define _eio_stat(p, b) stat(p, b) +#define _eio_lstat(p, b) lstat(p, b) +#endif + +/* Keeping 32 Eio_File_Progress alive should be enought */ +#define EIO_PROGRESS_LIMIT 32 + +/* Huge TLB == 16M on most system */ +#define EIO_PACKET_SIZE 65536 +#define EIO_PACKET_COUNT 256 + +#define EIO_PACKED_TIME 0.003 + +extern int _eio_log_dom_global; + +#ifdef EIO_DEFAULT_LOG_COLOR +# undef EIO_DEFAULT_LOG_COLOR +#endif /* ifdef EIO_DEFAULT_LOG_COLOR */ +#define EIO_DEFAULT_LOG_COLOR EINA_COLOR_CYAN +#ifdef ERR +# undef ERR +#endif /* ifdef ERR */ +#define ERR(...) EINA_LOG_DOM_ERR(_eio_log_dom_global, __VA_ARGS__) +#ifdef DBG +# undef DBG +#endif /* ifdef DBG */ +#define DBG(...) EINA_LOG_DOM_DBG(_eio_log_dom_global, __VA_ARGS__) +#ifdef INF +# undef INF +#endif /* ifdef INF */ +#define INF(...) EINA_LOG_DOM_INFO(_eio_log_dom_global, __VA_ARGS__) +#ifdef WRN +# undef WRN +#endif /* ifdef WRN */ +#define WRN(...) EINA_LOG_DOM_WARN(_eio_log_dom_global, __VA_ARGS__) +#ifdef CRIT +# undef CRIT +#endif /* ifdef CRIT */ +#define CRIT(...) EINA_LOG_DOM_CRIT(_eio_log_dom_global, __VA_ARGS__) + +typedef struct _Eio_Eet_Open Eio_Eet_Open; +typedef struct _Eio_Eet_Simple Eio_Eet_Simple; +typedef struct _Eio_Eet_Write Eio_Eet_Write; +typedef struct _Eio_Eet_Read Eio_Eet_Read; +typedef struct _Eio_Eet_Image_Write Eio_Eet_Image_Write; +typedef struct _Eio_File_Map Eio_File_Map; +typedef struct _Eio_File_Map_Rule Eio_File_Map_Rule; +typedef struct _Eio_File_Ls Eio_File_Ls; +typedef struct _Eio_File_Direct_Ls Eio_File_Direct_Ls; +typedef struct _Eio_File_Dir_Ls Eio_File_Dir_Ls; +typedef struct _Eio_File_Char_Ls Eio_File_Char_Ls; +typedef struct _Eio_File_Mkdir Eio_File_Mkdir; +typedef struct _Eio_File_Mkdir Eio_File_Chmod; +typedef struct _Eio_File_Unlink Eio_File_Unlink; +typedef struct _Eio_File_Stat Eio_File_Stat; +typedef struct _Eio_File_Progress Eio_File_Progress; +typedef struct _Eio_File_Move Eio_File_Move; +typedef struct _Eio_File_Chown Eio_File_Chown; +typedef struct _Eio_Monitor_Backend Eio_Monitor_Backend; + +typedef struct _Eio_File_Xattr Eio_File_Xattr; + +typedef struct _Eio_Dir_Copy Eio_Dir_Copy; + +typedef struct _Eio_File_Direct_Info Eio_File_Direct_Info; +typedef struct _Eio_File_Char Eio_File_Char; + +typedef struct _Eio_File_Associate Eio_File_Associate; + +struct _Eio_File_Associate +{ + void *data; + + Eina_Free_Cb free_cb; +}; + +struct _Eio_File_Direct_Info +{ + Eina_File_Direct_Info info; + + Eina_Hash *associated; +}; + +struct _Eio_File_Char +{ + const char *filename; + + Eina_Hash *associated; +}; + +struct _Eio_File +{ + Ecore_Thread *thread; + const void *data; + void *container; + + int error; + + Eio_Error_Cb error_cb; + Eio_Done_Cb done_cb; + + struct { + Eina_Hash *associated; + } worker, main; +}; + +struct _Eio_Eet_Simple +{ + Eio_File common; + + Eet_File *ef; + Eio_Eet_Error_Cb error_cb; + Eet_Error error; +}; + +struct _Eio_Eet_Write +{ + Eio_File common; + + Eet_File *ef; + Eet_Data_Descriptor *edd; + const char *name; + const char *cipher_key; + void *write_data; + int compress; + int size; + + int result; + Eio_Done_Int_Cb done_cb; +}; + +struct _Eio_Eet_Read +{ + Eio_File common; + + Eet_File *ef; + Eet_Data_Descriptor *edd; + const char *name; + const char *cipher_key; + + int size; + + void *result; + union { + Eio_Done_ERead_Cb eread; + Eio_Done_Data_Cb data; + Eio_Done_Read_Cb read; + } done_cb; +}; + +struct _Eio_Eet_Image_Write +{ + Eio_File common; + + Eet_File *ef; + const char *name; + const char *cipher_key; + void *write_data; + + unsigned int w; + unsigned int h; + int alpha; + int compress; + int quality; + int lossy; + + int result; + Eio_Done_Int_Cb done_cb; +}; + +struct _Eio_Eet_Open +{ + Eio_File common; + + Eio_Eet_Open_Cb eet_cb; + const char *filename; + Eet_File_Mode mode; + + Eet_File *result; +}; + +struct _Eio_File_Map +{ + Eio_File common; + + Eio_Open_Cb open_cb; + const char *name; + Eina_Bool shared; + + Eina_File *result; +}; + +struct _Eio_File_Map_Rule +{ + Eio_File common; + Eio_Filter_Map_Cb filter_cb; + Eio_Map_Cb map_cb; + + Eina_File_Populate rule; + Eina_File *file; + + unsigned long int offset; + unsigned long int length; + + void *result; +}; + +struct _Eio_File_Ls +{ + Eio_File common; + const char *directory; +}; + +struct _Eio_File_Direct_Ls +{ + Eio_File_Ls ls; + + Eio_Filter_Direct_Cb filter_cb; + Eio_Main_Direct_Cb main_cb; + + Eina_List *pack; + double start; +}; + +struct _Eio_File_Dir_Ls +{ + Eio_File_Ls ls; + + Eio_Filter_Dir_Cb filter_cb; + Eio_Main_Direct_Cb main_cb; + + Eina_List *pack; + double start; +}; + +struct _Eio_File_Char_Ls +{ + Eio_File_Ls ls; + + Eio_Filter_Cb filter_cb; + Eio_Main_Cb main_cb; +}; + +struct _Eio_File_Mkdir +{ + Eio_File common; + + const char *path; + mode_t mode; +}; + +struct _Eio_File_Unlink +{ + Eio_File common; + + const char *path; +}; + +struct _Eio_File_Stat +{ + Eio_File common; + + Eio_Stat_Cb done_cb; + + Eina_Stat buffer; + const char *path; +}; + +typedef enum { + EIO_XATTR_DATA, + EIO_XATTR_STRING, + EIO_XATTR_DOUBLE, + EIO_XATTR_INT +} Eio_File_Xattr_Op; + +struct _Eio_File_Xattr +{ + Eio_File common; + + const char *path; + const char *attribute; + Eina_Xattr_Flags flags; + + Eio_File_Xattr_Op op; + + union { + struct { + Eio_Done_Data_Cb done_cb; + + char *xattr_data; + ssize_t xattr_size; + } xdata; + struct { + Eio_Done_String_Cb done_cb; + + char *xattr_string; + } xstring; + struct { + Eio_Done_Double_Cb done_cb; + + double xattr_double; + } xdouble; + struct { + Eio_Done_Int_Cb done_cb; + + int xattr_int; + } xint; + } todo; + + Eina_Bool set : 1; +}; + +struct _Eio_File_Progress +{ + Eio_File common; + + Eio_Progress_Cb progress_cb; + + const char *source; + const char *dest; + + Eio_File_Op op; +}; + +struct _Eio_File_Move +{ + Eio_File_Progress progress; + + Eio_File *copy; +}; + +struct _Eio_Dir_Copy +{ + Eio_File_Progress progress; + Eio_Filter_Direct_Cb filter_cb; + + Eina_List *files; + Eina_List *dirs; + Eina_List *links; +}; + +struct _Eio_File_Chown +{ + Eio_File common; + + const char *path; + const char *user; + const char *group; +}; + +struct _Eio_Monitor +{ + Eio_Monitor_Backend *backend; + Eio_File *exist; + + const char *path; + + EINA_REFCOUNT; + int error; + + time_t mtime; + + Eina_Bool fallback : 1; + Eina_Bool rename : 1; + Eina_Bool delete_me : 1; +}; + +/* Be aware that ecore_thread_run could call cancel_cb if something goes wrong. */ +Eina_Bool eio_file_set(Eio_File *common, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data, + Ecore_Thread_Cb job_cb, + Ecore_Thread_Cb end_cb, + Ecore_Thread_Cb cancel_cb); + +/* Be aware that ecore_thread_run could call cancel_cb if something goes wrong. */ +Eina_Bool eio_long_file_set(Eio_File *common, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data, + Ecore_Thread_Cb heavy_cb, + Ecore_Thread_Notify_Cb notify_cb, + Ecore_Thread_Cb end_cb, + Ecore_Thread_Cb cancel_cb); + +void eio_file_free(Eio_File *common); +void eio_async_free(Eio_File_Ls *async); + +void eio_file_container_set(Eio_File *common, void *container); + +void eio_file_error(Eio_File *common); +void eio_file_thread_error(Eio_File *common, Ecore_Thread *thread); + +Eio_File_Direct_Info *eio_direct_info_malloc(void); +void eio_direct_info_free(Eio_File_Direct_Info *data); + +Eio_File_Char *eio_char_malloc(void); +void eio_char_free(Eio_File_Char *data); + +Eio_File_Associate *eio_associate_malloc(const void *data, Eina_Free_Cb free_cb); +void eio_associate_free(void *data); + +Eio_Progress *eio_progress_malloc(void); +void eio_progress_free(Eio_Progress *progress); + +void eio_progress_send(Ecore_Thread *thread, Eio_File_Progress *op, + long long current, long long max); +void eio_progress_cb(Eio_Progress *progress, Eio_File_Progress *op); + +Eina_Bool eio_file_copy_do(Ecore_Thread *thread, Eio_File_Progress *copy); + +void eio_monitor_init(void); +void eio_monitor_backend_init(void); +void eio_monitor_fallback_init(void); + +void eio_monitor_shutdown(void); +void eio_monitor_backend_shutdown(void); +void eio_monitor_fallback_shutdown(void); +void eio_monitor_backend_add(Eio_Monitor *monitor); +void eio_monitor_fallback_add(Eio_Monitor *monitor); + +void eio_monitor_backend_del(Eio_Monitor *monitor); +void eio_monitor_fallback_del(Eio_Monitor *monitor); + +void _eio_monitor_send(Eio_Monitor *monitor, const char *filename, int event_code); +void _eio_monitor_rename(Eio_Monitor *monitor, const char *newpath); + +void eio_async_end(void *data, Ecore_Thread *thread); +void eio_async_error(void *data, Ecore_Thread *thread); + +#endif diff --git a/src/lib/eio_single.c b/src/lib/eio_single.c new file mode 100644 index 0000000..8bc99fa --- /dev/null +++ b/src/lib/eio_single.c @@ -0,0 +1,594 @@ +/* EIO - EFL data type library + * Copyright (C) 2010 Enlightenment Developers: + * Cedric Bail + * Vincent "caro" Torri + * Stephen "okra" Houston + * + * 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 . + */ +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +static void +_eio_file_mkdir(void *data, Ecore_Thread *thread) +{ + Eio_File_Mkdir *m = data; + + if (mkdir(m->path, m->mode) != 0) + eio_file_thread_error(&m->common, thread); +} + +static void +_eio_mkdir_free(Eio_File_Mkdir *m) +{ + eina_stringshare_del(m->path); + eio_file_free(&m->common); +} + +static void +_eio_file_mkdir_done(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Mkdir *m = data; + + if (m->common.done_cb) + m->common.done_cb((void*) m->common.data, &m->common); + + _eio_mkdir_free(m); +} + +static void +_eio_file_mkdir_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Mkdir *m = data; + + eio_file_error(&m->common); + _eio_mkdir_free(m); +} + +static void +_eio_file_unlink(void *data, Ecore_Thread *thread) +{ + Eio_File_Unlink *l = data; + + if (unlink(l->path) != 0) + eio_file_thread_error(&l->common, thread); +} + +static void +_eio_unlink_free(Eio_File_Unlink *l) +{ + eina_stringshare_del(l->path); + eio_file_free(&l->common); +} + +static void +_eio_file_unlink_done(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Unlink *l = data; + + if (l->common.done_cb) + l->common.done_cb((void*) l->common.data, &l->common); + + _eio_unlink_free(l); +} + +static void +_eio_file_unlink_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Unlink *l = data; + + eio_file_error(&l->common); + _eio_unlink_free(l); +} + +static void +_eio_file_struct_2_eina(Eina_Stat *es, _eio_stat_t *st) +{ + es->dev = st->st_dev; + es->ino = st->st_ino; + es->mode = st->st_mode; + es->nlink = st->st_nlink; + es->uid = st->st_uid; + es->gid = st->st_gid; + es->rdev = st->st_rdev; + es->size = st->st_size; +#ifdef _WIN32 + es->blksize = 0; + es->blocks = 0; +#else + es->blksize = st->st_blksize; + es->blocks = st->st_blocks; +#endif + es->atime = st->st_atime; + es->mtime = st->st_mtime; + es->ctime = st->st_ctime; +#ifdef _STAT_VER_LINUX +# if (defined __USE_MISC && defined st_mtime) + es->atimensec = st->st_atim.tv_nsec; + es->mtimensec = st->st_mtim.tv_nsec; + es->ctimensec = st->st_ctim.tv_nsec; +# else + es->atimensec = st->st_atimensec; + es->mtimensec = st->st_mtimensec; + es->ctimensec = st->st_ctimensec; +# endif +#else + es->atimensec = 0; + es->mtimensec = 0; + es->ctimensec = 0; +#endif +} + +static void +_eio_file_stat(void *data, Ecore_Thread *thread) +{ + Eio_File_Stat *s = data; + _eio_stat_t buf; + + if (_eio_stat(s->path, &buf) != 0) + eio_file_thread_error(&s->common, thread); + + _eio_file_struct_2_eina(&s->buffer, &buf); +} + +#ifdef HAVE_LSTAT +static void +_eio_file_lstat(void *data, Ecore_Thread *thread) +{ + Eio_File_Stat *s = data; + struct stat buf; + + if (lstat(s->path, &buf) != 0) + eio_file_thread_error(&s->common, thread); + + _eio_file_struct_2_eina(&s->buffer, &buf); +} +#endif + +static void +_eio_stat_free(Eio_File_Stat *s) +{ + eina_stringshare_del(s->path); + eio_file_free(&s->common); +} + +static void +_eio_file_stat_done(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Stat *s = data; + + if (s->done_cb) + s->done_cb((void*) s->common.data, &s->common, &s->buffer); + + _eio_stat_free(s); +} + +static void +_eio_file_stat_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Stat *s = data; + + eio_file_error(&s->common); + _eio_stat_free(s); +} + +static void +_eio_file_chmod(void *data, Ecore_Thread *thread) +{ + Eio_File_Chmod *ch = data; + + if (chmod(ch->path, ch->mode) != 0) + eio_file_thread_error(&ch->common, thread); +} + +static void +_eio_file_chown(void *data, Ecore_Thread *thread) +{ +#ifdef _WIN32 + /* FIXME: + * look at http://wwwthep.physik.uni-mainz.de/~frink/chown/readme.html + */ + (void)data; + (void)thread; +#else + Eio_File_Chown *own = data; + char *tmp; + uid_t owner = -1; + gid_t group = -1; + + own->common.error = 0; + + if (own->user) + { + owner = strtol(own->user, &tmp, 10); + + if (*tmp != '\0') + { + struct passwd *pw = NULL; + + own->common.error = EIO_FILE_GETPWNAM; + + pw = getpwnam(own->user); + if (!pw) goto on_error; + + owner = pw->pw_uid; + } + } + + if (own->group) + { + group = strtol(own->group, &tmp, 10); + + if (*tmp != '\0') + { + struct group *grp = NULL; + + own->common.error = EIO_FILE_GETGRNAM; + + grp = getgrnam(own->group); + if (!grp) goto on_error; + + group = grp->gr_gid; + } + } + + if (owner == (uid_t) -1 && group == (gid_t) -1) + goto on_error; + + if (chown(own->path, owner, group) != 0) + eio_file_thread_error(&own->common, thread); + + return ; + + on_error: + ecore_thread_cancel(thread); + return ; +#endif +} + +static void +_eio_chown_free(Eio_File_Chown *ch) +{ + if (ch->user) eina_stringshare_del(ch->user); + if (ch->group) eina_stringshare_del(ch->group); + eina_stringshare_del(ch->path); + eio_file_free(&ch->common); +} + +static void +_eio_file_chown_done(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Chown *ch = data; + + if (ch->common.done_cb) + ch->common.done_cb((void*) ch->common.data, &ch->common); + + _eio_chown_free(ch); +} + +static void +_eio_file_chown_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Chown *ch = data; + + eio_file_error(&ch->common); + _eio_chown_free(ch); +} + +/** + * @endcond + */ + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +void +eio_file_error(Eio_File *common) +{ + if (common->error_cb) + common->error_cb((void*) common->data, common, common->error); +} + +void +eio_file_thread_error(Eio_File *common, Ecore_Thread *thread) +{ + common->error = errno; + ecore_thread_cancel(thread); +} + +void +eio_file_free(Eio_File *common) +{ + if (common->worker.associated) + eina_hash_free(common->worker.associated); + if (common->main.associated) + eina_hash_free(common->main.associated); + free(common); +} + +Eina_Bool +eio_long_file_set(Eio_File *common, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data, + Ecore_Thread_Cb heavy_cb, + Ecore_Thread_Notify_Cb notify_cb, + Ecore_Thread_Cb end_cb, + Ecore_Thread_Cb cancel_cb) +{ + Ecore_Thread *thread; + + common->done_cb = done_cb; + common->error_cb = error_cb; + common->data = data; + common->error = 0; + common->thread = NULL; + common->container = NULL; + common->worker.associated = NULL; + common->main.associated = NULL; + + /* Be aware that ecore_thread_feedback_run could call cancel_cb if something goes wrong. + This means that common would be destroyed if thread == NULL. + */ + thread = ecore_thread_feedback_run(heavy_cb, + notify_cb, + end_cb, + cancel_cb, + common, + EINA_FALSE); + if (thread) common->thread = thread; + return !!thread; +} + +Eina_Bool +eio_file_set(Eio_File *common, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data, + Ecore_Thread_Cb job_cb, + Ecore_Thread_Cb end_cb, + Ecore_Thread_Cb cancel_cb) +{ + Ecore_Thread *thread; + + common->done_cb = done_cb; + common->error_cb = error_cb; + common->data = data; + common->error = 0; + common->thread = NULL; + common->container = NULL; + common->worker.associated = NULL; + common->main.associated = NULL; + + /* Be aware that ecore_thread_run could call cancel_cb if something goes wrong. + This means that common would be destroyed if thread == NULL. + */ + thread = ecore_thread_run(job_cb, end_cb, cancel_cb, common); + + if (thread) common->thread = thread; + return !!thread; +} + +void +eio_file_container_set(Eio_File *common, void *container) +{ + common->container = container; +} + +/** + * @endcond + */ + + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI Eio_File * +eio_file_direct_stat(const char *path, + Eio_Stat_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Stat *s = NULL; + + if (!path || !done_cb || !error_cb) + return NULL; + + s = malloc(sizeof (Eio_File_Stat)); + if (!s) return NULL; + + s->path = eina_stringshare_add(path); + s->done_cb = done_cb; + + if (!eio_file_set(&s->common, + NULL, + error_cb, + data, + _eio_file_stat, + _eio_file_stat_done, + _eio_file_stat_error)) + /* THERE IS NO MEMLEAK HERE, ECORE_THREAD CANCEL CALLBACK HAS BEEN ALREADY CALLED + AND s HAS BEEN FREED, SAME FOR ALL CALL TO EIO_FILE_SET ! */ + return NULL; + + return &s->common; +} + +EAPI Eio_File * +eio_file_direct_lstat(const char *path, + Eio_Stat_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ +#ifdef HAVE_LSTAT + Eio_File_Stat *s = NULL; + + if (!path || !done_cb || !error_cb) + return NULL; + + s = malloc(sizeof (Eio_File_Stat)); + if (!s) return NULL; + + s->path = eina_stringshare_add(path); + s->done_cb = done_cb; + + if (!eio_file_set(&s->common, + NULL, + error_cb, + data, + _eio_file_lstat, + _eio_file_stat_done, + _eio_file_stat_error)) + return NULL; + + return &s->common; +#else + return eio_file_direct_stat(path, done_cb, error_cb, data); +#endif +} + +EAPI Eio_File * +eio_file_unlink(const char *path, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Unlink *l = NULL; + + if (!path || !done_cb || !error_cb) + return NULL; + + l = malloc(sizeof (Eio_File_Unlink)); + if (!l) return NULL; + + l->path = eina_stringshare_add(path); + + if (!eio_file_set(&l->common, + done_cb, + error_cb, + data, + _eio_file_unlink, + _eio_file_unlink_done, + _eio_file_unlink_error)) + return NULL; + + return &l->common; +} + +EAPI Eio_File * +eio_file_mkdir(const char *path, + mode_t mode, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Mkdir *r = NULL; + + if (!path || !done_cb || !error_cb) + return NULL; + + r = malloc(sizeof (Eio_File_Mkdir)); + if (!r) return NULL; + + r->path = eina_stringshare_add(path); + r->mode = mode; + + if (!eio_file_set(&r->common, + done_cb, + error_cb, + data, + _eio_file_mkdir, + _eio_file_mkdir_done, + _eio_file_mkdir_error)) + return NULL; + + return &r->common; +} + +EAPI Eio_File * +eio_file_chmod(const char *path, + mode_t mode, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Mkdir *r = NULL; + + if (!path || !done_cb || !error_cb) + return NULL; + + r = malloc(sizeof (Eio_File_Mkdir)); + if (!r) return NULL; + + r->path = eina_stringshare_add(path); + r->mode = mode; + + if (!eio_file_set(&r->common, + done_cb, + error_cb, + data, + _eio_file_chmod, + _eio_file_mkdir_done, + _eio_file_mkdir_error)) + return NULL; + + return &r->common; +} + +EAPI Eio_File * +eio_file_chown(const char *path, + const char *user, + const char *group, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Chown *c = NULL; + + if (!path || !done_cb || !error_cb) + return NULL; + + c = malloc(sizeof (Eio_File_Chown)); + if (!c) return NULL; + + c->path = eina_stringshare_add(path); + c->user = eina_stringshare_add(user); + c->group = eina_stringshare_add(group); + + if (!eio_file_set(&c->common, + done_cb, + error_cb, + data, + _eio_file_chown, + _eio_file_chown_done, + _eio_file_chown_error)) + return NULL; + + return &c->common; +} diff --git a/src/lib/eio_xattr.c b/src/lib/eio_xattr.c new file mode 100644 index 0000000..cff21b9 --- /dev/null +++ b/src/lib/eio_xattr.c @@ -0,0 +1,500 @@ +/* EIO - EFL data type library + * Copyright (C) 2011 Enlightenment Developers: + * 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 . + */ + +#include "eio_private.h" +#include "Eio.h" + +/*============================================================================* + * Local * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +static void +_eio_ls_xattr_heavy(void *data, Ecore_Thread *thread) +{ + Eio_File_Char_Ls *async = data; + Eina_Iterator *it; + const char *tmp; + + it = eina_xattr_ls(async->ls.directory); + if (!it) return ; + + EINA_ITERATOR_FOREACH(it, tmp) + { + Eina_Bool filter = EINA_TRUE; + + if (async->filter_cb) + { + filter = async->filter_cb((void*) async->ls.common.data, + &async->ls.common, + tmp); + } + + if (filter) ecore_thread_feedback(thread, eina_stringshare_add(tmp)); + + if (ecore_thread_check(thread)) + break; + } + + eina_iterator_free(it); +} + +static void +_eio_ls_xattr_notify(void *data, Ecore_Thread *thread __UNUSED__, void *msg_data) +{ + Eio_File_Char_Ls *async = data; + const char *xattr = msg_data; + + async->main_cb((void*) async->ls.common.data, &async->ls.common, xattr); +} + +static void +_eio_file_xattr_get(void *data, Ecore_Thread *thread) +{ + Eio_File_Xattr *async = data; + Eina_Bool failure = EINA_FALSE; + const char *file; + const char *attribute; + + file = async->path; + attribute = async->attribute; + + switch (async->op) + { + case EIO_XATTR_DATA: + async->todo.xdata.xattr_size = 0; + async->todo.xdata.xattr_data = NULL; + + async->todo.xdata.xattr_data = eina_xattr_get(file, attribute, &async->todo.xdata.xattr_size); + if (!async->todo.xdata.xattr_data) failure = EINA_TRUE; + break; + case EIO_XATTR_STRING: + async->todo.xstring.xattr_string = eina_xattr_string_get(file, attribute); + if (!async->todo.xstring.xattr_string) failure = EINA_TRUE; + break; + case EIO_XATTR_DOUBLE: + failure = !eina_xattr_double_get(file, attribute, &async->todo.xdouble.xattr_double); + break; + case EIO_XATTR_INT: + failure = !eina_xattr_int_get(file, attribute, &async->todo.xint.xattr_int); + break; + } + + if (failure) + ecore_thread_cancel(thread); +} + +static void +_eio_file_xattr_free(Eio_File_Xattr *async) +{ + eina_stringshare_del(async->path); + eina_stringshare_del(async->attribute); + if (!async->set) + { + if (async->op == EIO_XATTR_DATA) free(async->todo.xdata.xattr_data); + if (async->op == EIO_XATTR_STRING) free(async->todo.xstring.xattr_string); + } + eio_file_free(&async->common); +} + +static void +_eio_file_xattr_get_done(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Xattr *async = data; + + switch (async->op) + { + case EIO_XATTR_DATA: + if (async->todo.xdata.done_cb) + async->todo.xdata.done_cb((void *) async->common.data, &async->common, async->todo.xdata.xattr_data, async->todo.xdata.xattr_size); + break; + case EIO_XATTR_STRING: + if (async->todo.xstring.done_cb) + async->todo.xstring.done_cb((void *) async->common.data, &async->common, async->todo.xstring.xattr_string); + break; + case EIO_XATTR_DOUBLE: + if (async->todo.xdouble.done_cb) + async->todo.xdouble.done_cb((void *) async->common.data, &async->common, async->todo.xdouble.xattr_double); + break; + case EIO_XATTR_INT: + if (async->todo.xint.done_cb) + async->todo.xint.done_cb((void *) async->common.data, &async->common, async->todo.xint.xattr_int); + break; + } + + _eio_file_xattr_free(async); +} + +static void +_eio_file_xattr_get_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Xattr *async = data; + + eio_file_error(&async->common); + _eio_file_xattr_free(async); +} + +static void +_eio_file_xattr_set(void *data, Ecore_Thread *thread) +{ + Eio_File_Xattr *async = data; + const char *file; + const char *attribute; + Eina_Xattr_Flags flags; + Eina_Bool failure = EINA_FALSE; + + file = async->path; + attribute = async->attribute; + flags = async->flags; + + switch (async->op) + { + case EIO_XATTR_DATA: + failure = !eina_xattr_set(file, attribute, async->todo.xdata.xattr_data, async->todo.xdata.xattr_size, flags); + break; + case EIO_XATTR_STRING: + failure = !eina_xattr_string_set(file, attribute, async->todo.xstring.xattr_string, flags); + break; + case EIO_XATTR_DOUBLE: + failure = !eina_xattr_double_set(file, attribute, async->todo.xdouble.xattr_double, flags); + break; + case EIO_XATTR_INT: + failure = !eina_xattr_int_set(file, attribute, async->todo.xint.xattr_int, flags); + break; + } + + if (failure) eio_file_thread_error(&async->common, thread); +} + +static void +_eio_file_xattr_set_done(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Xattr *async = data; + + if (async->common.done_cb) + async->common.done_cb((void*) async->common.data, &async->common); + + _eio_file_xattr_free(async); +} + +static void +_eio_file_xattr_set_error(void *data, Ecore_Thread *thread __UNUSED__) +{ + Eio_File_Xattr *async = data; + + eio_file_error(&async->common); + _eio_file_xattr_free(async); +} + +static Eio_File * +_eio_file_xattr_setup_get(Eio_File_Xattr *async, + const char *path, + const char *attribute, + Eio_Error_Cb error_cb, + const void *data) +{ + async->path = eina_stringshare_add(path); + async->attribute = eina_stringshare_add(attribute); + async->set = EINA_FALSE; + + if (!eio_file_set(&async->common, + NULL, + error_cb, + data, + _eio_file_xattr_get, + _eio_file_xattr_get_done, + _eio_file_xattr_get_error)) + return NULL; + + return &async->common; +} + +static Eio_File * +_eio_file_xattr_setup_set(Eio_File_Xattr *async, + const char *path, + const char *attribute, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + async->path = eina_stringshare_add(path); + async->attribute = eina_stringshare_add(attribute); + async->flags = flags; + async->set = EINA_TRUE; + + if (!eio_file_set(&async->common, + done_cb, + error_cb, + data, + _eio_file_xattr_set, + _eio_file_xattr_set_done, + _eio_file_xattr_set_error)) + return NULL; + + return &async->common; +} + +/** + * @endcond + */ + + +/*============================================================================* + * Global * + *============================================================================*/ + +/** + * @cond LOCAL + */ + +/** + * @endcond + */ + + +/*============================================================================* + * API * + *============================================================================*/ + +EAPI Eio_File * +eio_file_xattr(const char *path, + Eio_Filter_Cb filter_cb, + Eio_Main_Cb main_cb, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Char_Ls *async; + + EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(main_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(done_cb, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(error_cb, NULL); + + async = malloc(sizeof (Eio_File_Char_Ls)); + EINA_SAFETY_ON_NULL_RETURN_VAL(async, NULL); + + async->filter_cb = filter_cb; + async->main_cb = main_cb; + async->ls.directory = eina_stringshare_add(path); + + if (!eio_long_file_set(&async->ls.common, + done_cb, + error_cb, + data, + _eio_ls_xattr_heavy, + _eio_ls_xattr_notify, + eio_async_end, + eio_async_error)) + return NULL; + + return &async->ls.common; +} + +EAPI Eio_File * +eio_file_xattr_get(const char *path, + const char *attribute, + Eio_Done_Data_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + + if (!path || !attribute || !done_cb || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr)); + if (!async) return NULL; + + async->op = EIO_XATTR_DATA; + async->todo.xdata.done_cb = done_cb; + + return _eio_file_xattr_setup_get(async, path, attribute, error_cb, data); +} + +EAPI Eio_File * +eio_file_xattr_string_get(const char *path, + const char *attribute, + Eio_Done_String_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + + if (!path || !attribute || !done_cb || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr)); + if (!async) return NULL; + + async->op = EIO_XATTR_STRING; + async->todo.xstring.done_cb = done_cb; + + return _eio_file_xattr_setup_get(async, path, attribute, error_cb, data); +} + +EAPI Eio_File * +eio_file_xattr_double_get(const char *path, + const char *attribute, + Eio_Done_Double_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + + if (!path || !attribute || !done_cb || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr)); + if (!async) return NULL; + + async->op = EIO_XATTR_DOUBLE; + async->todo.xdouble.done_cb = done_cb; + + return _eio_file_xattr_setup_get(async, path, attribute, error_cb, data); +} + +EAPI Eio_File * +eio_file_xattr_int_get(const char *path, + const char *attribute, + Eio_Done_Int_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + + if (!path || !attribute || !done_cb || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr)); + if (!async) return NULL; + + async->op = EIO_XATTR_INT; + async->todo.xint.done_cb = done_cb; + + return _eio_file_xattr_setup_get(async, path, attribute, error_cb, data); +} + +EAPI Eio_File * +eio_file_xattr_set(const char *path, + const char *attribute, + const char *xattr_data, + unsigned int xattr_size, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + + if (!path || !attribute || !done_cb || !xattr_data || !xattr_size || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr) + xattr_size); + if (!async) return NULL; + + async->op = EIO_XATTR_DATA; + async->todo.xdata.xattr_size = xattr_size; + async->todo.xdata.xattr_data = (char*) (async + 1); + memcpy(async->todo.xdata.xattr_data, xattr_data, xattr_size); + + return _eio_file_xattr_setup_set(async, path, attribute, flags, done_cb, error_cb, data); +} + +EAPI Eio_File * +eio_file_xattr_string_set(const char *path, + const char *attribute, + const char *xattr_string, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + int length; + + if (!path || !attribute || !done_cb || !xattr_string || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr)); + if (!async) return NULL; + + length = strlen(xattr_string) + 1; + + async->op = EIO_XATTR_STRING; + async->todo.xstring.xattr_string = malloc(length); + if (!async->todo.xstring.xattr_string) + { + free(async); + return NULL; + } + memcpy(async->todo.xstring.xattr_string, xattr_string, length); + + return _eio_file_xattr_setup_set(async, path, attribute, flags, done_cb, error_cb, data); +} + +EAPI Eio_File * +eio_file_xattr_double_set(const char *path, + const char *attribute, + double xattr_double, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + + if (!path || !attribute || !done_cb || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr)); + if (!async) return NULL; + + async->op = EIO_XATTR_DOUBLE; + async->todo.xdouble.xattr_double = xattr_double; + + return _eio_file_xattr_setup_set(async, path, attribute, flags, done_cb, error_cb, data); +} + +EAPI Eio_File * +eio_file_xattr_int_set(const char *path, + const char *attribute, + int xattr_int, + Eina_Xattr_Flags flags, + Eio_Done_Cb done_cb, + Eio_Error_Cb error_cb, + const void *data) +{ + Eio_File_Xattr *async; + + if (!path || !attribute || !done_cb || !error_cb) + return NULL; + + async = malloc(sizeof (Eio_File_Xattr)); + if (!async) return NULL; + + async->op = EIO_XATTR_INT; + async->todo.xint.xattr_int = xattr_int; + + return _eio_file_xattr_setup_set(async, path, attribute, flags, done_cb, error_cb, data); +} -- 2.7.4