Tizen 2.1 base
authorJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:52:57 +0000 (01:52 +0900)
committerJinkun Jang <jinkun.jang@samsung.com>
Tue, 12 Mar 2013 16:52:57 +0000 (01:52 +0900)
48 files changed:
AUTHORS
COPYING
ChangeLog
Makefile.am
NEWS
README
TODO [new file with mode: 0644]
autogen.sh
configure.ac
doc/Doxyfile.in [new file with mode: 0644]
doc/Makefile.am [new file with mode: 0644]
doc/e.css [new file with mode: 0644]
doc/eio.dox.in [new file with mode: 0644]
doc/foot.html [new file with mode: 0644]
doc/head.html [new file with mode: 0644]
doc/img/e.png [new file with mode: 0644]
doc/img/edoxy.css [new file with mode: 0644]
doc/img/foot_bg.png [new file with mode: 0644]
doc/img/head_bg.png [new file with mode: 0644]
doc/img/menu_bg.png [new file with mode: 0644]
doc/img/menu_bg_current.png [new file with mode: 0644]
doc/img/menu_bg_hover.png [new file with mode: 0644]
doc/img/menu_bg_last.png [new file with mode: 0644]
doc/img/menu_bg_unsel.png [new file with mode: 0644]
eio.manifest [new file with mode: 0644]
eio.spec.in [new file with mode: 0644]
m4/efl_examples.m4 [new file with mode: 0644]
m4/efl_threads.m4 [new file with mode: 0644]
m4/eio_check_options.m4 [new file with mode: 0644]
packaging/eio.spec [new file with mode: 0644]
src/Makefile.am
src/examples/Makefile.am [new file with mode: 0644]
src/examples/eio_file_ls.c [new file with mode: 0644]
src/lib/Eio.h
src/lib/Makefile.am
src/lib/eio_dir.c [new file with mode: 0644]
src/lib/eio_eet.c [new file with mode: 0644]
src/lib/eio_file.c
src/lib/eio_inline_helper.x [new file with mode: 0644]
src/lib/eio_main.c [new file with mode: 0644]
src/lib/eio_map.c [new file with mode: 0644]
src/lib/eio_monitor.c [new file with mode: 0644]
src/lib/eio_monitor_inotify.c [new file with mode: 0644]
src/lib/eio_monitor_poll.c [new file with mode: 0644]
src/lib/eio_monitor_win32.c [new file with mode: 0644]
src/lib/eio_private.h [new file with mode: 0644]
src/lib/eio_single.c [new file with mode: 0644]
src/lib/eio_xattr.c [new file with mode: 0644]

diff --git a/AUTHORS b/AUTHORS
index 8266484..27aeadc 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -1 +1,8 @@
 Cedric Bail <cedric.bail@free.fr>
+Stephen Houston <UnixTitan@gmail.com>
+Gustavo Sverzut Barbieri <barbieri@gmail.com>
+Vincent "caro" Torri <vtorri at univ-evry dot fr>
+Mikael SANS <sans.mikael@gmail.com>
+Mike Blumenkrantz (zmike/discomfitor) <michael.blumenkrantz@gmail.com>
+Jérôme Pinot <ngc891@gmail.com>
+Daniel Willmann <d.willmann@samsung.com>
diff --git a/COPYING b/COPYING
index cf546d2..63f364e 100644 (file)
--- 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
+\f
                  GNU LESSER GENERAL PUBLIC LICENSE
                       Version 2.1, February 1999
 
index e69de29..bc42978 100644 (file)
--- 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().
index eaf2bb9..2fad093 100644 (file)
@@ -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 (file)
--- 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 (file)
--- 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 (file)
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
index 995ff2f..00116ea 100755 (executable)
@@ -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
index a45911c..4f14a6a 100644 (file)
@@ -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 <unistd.h>
+#endif
+#include <fcntl.h>
+   ],
+   [
+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 <sys/types.h>
+#include <sys/stat.h>
+#if defined(HAVE_UNISTD_H)
+# include <unistd.h>
+#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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/xattr.h>
+       ]],
+       [[
+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 (file)
index 0000000..dbcc001
--- /dev/null
@@ -0,0 +1,1630 @@
+# Doxyfile 1.7.1\r
+\r
+# This file describes the settings to be used by the documentation system\r
+# doxygen (www.doxygen.org) for a project\r
+#\r
+# All text after a hash (#) is considered a comment and will be ignored\r
+# The format is:\r
+#       TAG = value [value, ...]\r
+# For lists items can also be appended using:\r
+#       TAG += value [value, ...]\r
+# Values that contain spaces should be placed between quotes (" ")\r
+\r
+#---------------------------------------------------------------------------\r
+# Project related configuration options\r
+#---------------------------------------------------------------------------\r
+\r
+# This tag specifies the encoding used for all characters in the config file\r
+# that follow. The default is UTF-8 which is also the encoding used for all\r
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the\r
+# iconv built into libc) for the transcoding. See\r
+# http://www.gnu.org/software/libiconv for the list of possible encodings.\r
+\r
+DOXYFILE_ENCODING      = UTF-8\r
+\r
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded\r
+# by quotes) that should identify the project.\r
+\r
+PROJECT_NAME           = Eio\r
+\r
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.\r
+# This could be handy for archiving the generated documentation or\r
+# if some version control system is used.\r
+\r
+PROJECT_NUMBER         = @PACKAGE_VERSION@\r
+\r
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)\r
+# base path where the generated documentation will be put.\r
+# If a relative path is entered, it will be relative to the location\r
+# where doxygen was started. If left blank the current directory will be used.\r
+\r
+OUTPUT_DIRECTORY       = .\r
+\r
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create\r
+# 4096 sub-directories (in 2 levels) under the output directory of each output\r
+# format and will distribute the generated files over these directories.\r
+# Enabling this option can be useful when feeding doxygen a huge amount of\r
+# source files, where putting all generated files in the same directory would\r
+# otherwise cause performance problems for the file system.\r
+\r
+CREATE_SUBDIRS         = NO\r
+\r
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all\r
+# documentation generated by doxygen is written. Doxygen will use this\r
+# information to generate all constant output in the proper language.\r
+# The default language is English, other supported languages are:\r
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,\r
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,\r
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English\r
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,\r
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,\r
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.\r
+\r
+OUTPUT_LANGUAGE        = English\r
+\r
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will\r
+# include brief member descriptions after the members that are listed in\r
+# the file and class documentation (similar to JavaDoc).\r
+# Set to NO to disable this.\r
+\r
+BRIEF_MEMBER_DESC      = YES\r
+\r
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend\r
+# the brief description of a member or function before the detailed description.\r
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the\r
+# brief descriptions will be completely suppressed.\r
+\r
+REPEAT_BRIEF           = YES\r
+\r
+# This tag implements a quasi-intelligent brief description abbreviator\r
+# that is used to form the text in various listings. Each string\r
+# in this list, if found as the leading text of the brief description, will be\r
+# stripped from the text and the result after processing the whole list, is\r
+# used as the annotated text. Otherwise, the brief description is used as-is.\r
+# If left blank, the following values are used ("$name" is automatically\r
+# replaced with the name of the entity): "The $name class" "The $name widget"\r
+# "The $name file" "is" "provides" "specifies" "contains"\r
+# "represents" "a" "an" "the"\r
+\r
+ABBREVIATE_BRIEF       =\r
+\r
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then\r
+# Doxygen will generate a detailed section even if there is only a brief\r
+# description.\r
+\r
+ALWAYS_DETAILED_SEC    = NO\r
+\r
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all\r
+# inherited members of a class in the documentation of that class as if those\r
+# members were ordinary class members. Constructors, destructors and assignment\r
+# operators of the base classes will not be shown.\r
+\r
+INLINE_INHERITED_MEMB  = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full\r
+# path before files name in the file list and in the header files. If set\r
+# to NO the shortest path that makes the file name unique will be used.\r
+\r
+FULL_PATH_NAMES        = NO\r
+\r
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag\r
+# can be used to strip a user-defined part of the path. Stripping is\r
+# only done if one of the specified strings matches the left-hand part of\r
+# the path. The tag can be used to show relative paths in the file list.\r
+# If left blank the directory from which doxygen is run is used as the\r
+# path to strip.\r
+\r
+STRIP_FROM_PATH        =\r
+\r
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of\r
+# the path mentioned in the documentation of a class, which tells\r
+# the reader which header file to include in order to use a class.\r
+# If left blank only the name of the header file containing the class\r
+# definition is used. Otherwise one should specify the include paths that\r
+# are normally passed to the compiler using the -I flag.\r
+\r
+STRIP_FROM_INC_PATH    =\r
+\r
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter\r
+# (but less readable) file names. This can be useful is your file systems\r
+# doesn't support long names like on DOS, Mac, or CD-ROM.\r
+\r
+SHORT_NAMES            = NO\r
+\r
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen\r
+# will interpret the first line (until the first dot) of a JavaDoc-style\r
+# comment as the brief description. If set to NO, the JavaDoc\r
+# comments will behave just like regular Qt-style comments\r
+# (thus requiring an explicit @brief command for a brief description.)\r
+\r
+JAVADOC_AUTOBRIEF      = NO\r
+\r
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will\r
+# interpret the first line (until the first dot) of a Qt-style\r
+# comment as the brief description. If set to NO, the comments\r
+# will behave just like regular Qt-style comments (thus requiring\r
+# an explicit \brief command for a brief description.)\r
+\r
+QT_AUTOBRIEF           = NO\r
+\r
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen\r
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///\r
+# comments) as a brief description. This used to be the default behaviour.\r
+# The new default is to treat a multi-line C++ comment block as a detailed\r
+# description. Set this tag to YES if you prefer the old behaviour instead.\r
+\r
+MULTILINE_CPP_IS_BRIEF = NO\r
+\r
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented\r
+# member inherits the documentation from any documented member that it\r
+# re-implements.\r
+\r
+INHERIT_DOCS           = YES\r
+\r
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce\r
+# a new page for each member. If set to NO, the documentation of a member will\r
+# be part of the file/class/namespace that contains it.\r
+\r
+SEPARATE_MEMBER_PAGES  = NO\r
+\r
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.\r
+# Doxygen uses this value to replace tabs by spaces in code fragments.\r
+\r
+TAB_SIZE               = 8\r
+\r
+# This tag can be used to specify a number of aliases that acts\r
+# as commands in the documentation. An alias has the form "name=value".\r
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to\r
+# put the command \sideeffect (or @sideeffect) in the documentation, which\r
+# will result in a user-defined paragraph with heading "Side Effects:".\r
+# You can put \n's in the value part of an alias to insert newlines.\r
+\r
+ALIASES                =\r
+\r
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C\r
+# sources only. Doxygen will then generate output that is more tailored for C.\r
+# For instance, some of the names that are used will be different. The list\r
+# of all members will be omitted, etc.\r
+\r
+OPTIMIZE_OUTPUT_FOR_C  = YES\r
+\r
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java\r
+# sources only. Doxygen will then generate output that is more tailored for\r
+# Java. For instance, namespaces will be presented as packages, qualified\r
+# scopes will look different, etc.\r
+\r
+OPTIMIZE_OUTPUT_JAVA   = NO\r
+\r
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran\r
+# sources only. Doxygen will then generate output that is more tailored for\r
+# Fortran.\r
+\r
+OPTIMIZE_FOR_FORTRAN   = NO\r
+\r
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL\r
+# sources. Doxygen will then generate output that is tailored for\r
+# VHDL.\r
+\r
+OPTIMIZE_OUTPUT_VHDL   = NO\r
+\r
+# Doxygen selects the parser to use depending on the extension of the files it\r
+# parses. With this tag you can assign which parser to use for a given extension.\r
+# Doxygen has a built-in mapping, but you can override or extend it using this\r
+# tag. The format is ext=language, where ext is a file extension, and language\r
+# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,\r
+# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make\r
+# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C\r
+# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions\r
+# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.\r
+\r
+EXTENSION_MAPPING      =\r
+\r
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want\r
+# to include (a tag file for) the STL sources as input, then you should\r
+# set this tag to YES in order to let doxygen match functions declarations and\r
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.\r
+# func(std::string) {}). This also make the inheritance and collaboration\r
+# diagrams that involve STL classes more complete and accurate.\r
+\r
+BUILTIN_STL_SUPPORT    = NO\r
+\r
+# If you use Microsoft's C++/CLI language, you should set this option to YES to\r
+# enable parsing support.\r
+\r
+CPP_CLI_SUPPORT        = NO\r
+\r
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.\r
+# Doxygen will parse them like normal C++ but will assume all classes use public\r
+# instead of private inheritance when no explicit protection keyword is present.\r
+\r
+SIP_SUPPORT            = NO\r
+\r
+# For Microsoft's IDL there are propget and propput attributes to indicate getter\r
+# and setter methods for a property. Setting this option to YES (the default)\r
+# will make doxygen to replace the get and set methods by a property in the\r
+# documentation. This will only work if the methods are indeed getting or\r
+# setting a simple type. If this is not the case, or you want to show the\r
+# methods anyway, you should set this option to NO.\r
+\r
+IDL_PROPERTY_SUPPORT   = YES\r
+\r
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC\r
+# tag is set to YES, then doxygen will reuse the documentation of the first\r
+# member in the group (if any) for the other members of the group. By default\r
+# all members of a group must be documented explicitly.\r
+\r
+DISTRIBUTE_GROUP_DOC   = NO\r
+\r
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of\r
+# the same type (for instance a group of public functions) to be put as a\r
+# subgroup of that type (e.g. under the Public Functions section). Set it to\r
+# NO to prevent subgrouping. Alternatively, this can be done per class using\r
+# the \nosubgrouping command.\r
+\r
+SUBGROUPING            = YES\r
+\r
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum\r
+# is documented as struct, union, or enum with the name of the typedef. So\r
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct\r
+# with name TypeT. When disabled the typedef will appear as a member of a file,\r
+# namespace, or class. And the struct will be named TypeS. This can typically\r
+# be useful for C code in case the coding convention dictates that all compound\r
+# types are typedef'ed and only the typedef is referenced, never the tag name.\r
+\r
+TYPEDEF_HIDES_STRUCT   = NO\r
+\r
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to\r
+# determine which symbols to keep in memory and which to flush to disk.\r
+# When the cache is full, less often used symbols will be written to disk.\r
+# For small to medium size projects (<1000 input files) the default value is\r
+# probably good enough. For larger projects a too small cache size can cause\r
+# doxygen to be busy swapping symbols to and from disk most of the time\r
+# causing a significant performance penality.\r
+# If the system has enough physical memory increasing the cache will improve the\r
+# performance by keeping more symbols in memory. Note that the value works on\r
+# a logarithmic scale so increasing the size by one will rougly double the\r
+# memory usage. The cache size is given by this formula:\r
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,\r
+# corresponding to a cache size of 2^16 = 65536 symbols\r
+\r
+SYMBOL_CACHE_SIZE      = 0\r
+\r
+#---------------------------------------------------------------------------\r
+# Build related configuration options\r
+#---------------------------------------------------------------------------\r
+\r
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in\r
+# documentation are documented, even if no documentation was available.\r
+# Private class members and static file members will be hidden unless\r
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES\r
+\r
+EXTRACT_ALL            = NO\r
+\r
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class\r
+# will be included in the documentation.\r
+\r
+EXTRACT_PRIVATE        = NO\r
+\r
+# If the EXTRACT_STATIC tag is set to YES all static members of a file\r
+# will be included in the documentation.\r
+\r
+EXTRACT_STATIC         = YES\r
+\r
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)\r
+# defined locally in source files will be included in the documentation.\r
+# If set to NO only classes defined in header files are included.\r
+\r
+EXTRACT_LOCAL_CLASSES  = NO\r
+\r
+# This flag is only useful for Objective-C code. When set to YES local\r
+# methods, which are defined in the implementation section but not in\r
+# the interface are included in the documentation.\r
+# If set to NO (the default) only methods in the interface are included.\r
+\r
+EXTRACT_LOCAL_METHODS  = NO\r
+\r
+# If this flag is set to YES, the members of anonymous namespaces will be\r
+# extracted and appear in the documentation as a namespace called\r
+# 'anonymous_namespace{file}', where file will be replaced with the base\r
+# name of the file that contains the anonymous namespace. By default\r
+# anonymous namespace are hidden.\r
+\r
+EXTRACT_ANON_NSPACES   = NO\r
+\r
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all\r
+# undocumented members of documented classes, files or namespaces.\r
+# If set to NO (the default) these members will be included in the\r
+# various overviews, but no documentation section is generated.\r
+# This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_MEMBERS     = NO\r
+\r
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all\r
+# undocumented classes that are normally visible in the class hierarchy.\r
+# If set to NO (the default) these classes will be included in the various\r
+# overviews. This option has no effect if EXTRACT_ALL is enabled.\r
+\r
+HIDE_UNDOC_CLASSES     = NO\r
+\r
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all\r
+# friend (class|struct|union) declarations.\r
+# If set to NO (the default) these declarations will be included in the\r
+# documentation.\r
+\r
+HIDE_FRIEND_COMPOUNDS  = NO\r
+\r
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any\r
+# documentation blocks found inside the body of a function.\r
+# If set to NO (the default) these blocks will be appended to the\r
+# function's detailed documentation block.\r
+\r
+HIDE_IN_BODY_DOCS      = NO\r
+\r
+# The INTERNAL_DOCS tag determines if documentation\r
+# that is typed after a \internal command is included. If the tag is set\r
+# to NO (the default) then the documentation will be excluded.\r
+# Set it to YES to include the internal documentation.\r
+\r
+INTERNAL_DOCS          = NO\r
+\r
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate\r
+# file names in lower-case letters. If set to YES upper-case letters are also\r
+# allowed. This is useful if you have classes or files whose names only differ\r
+# in case and if your file system supports case sensitive file names. Windows\r
+# and Mac users are advised to set this option to NO.\r
+\r
+CASE_SENSE_NAMES       = YES\r
+\r
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen\r
+# will show members with their full class and namespace scopes in the\r
+# documentation. If set to YES the scope will be hidden.\r
+\r
+HIDE_SCOPE_NAMES       = NO\r
+\r
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen\r
+# will put a list of the files that are included by a file in the documentation\r
+# of that file.\r
+\r
+SHOW_INCLUDE_FILES     = NO\r
+\r
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen\r
+# will list include files with double quotes in the documentation\r
+# rather than with sharp brackets.\r
+\r
+FORCE_LOCAL_INCLUDES   = NO\r
+\r
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]\r
+# is inserted in the documentation for inline members.\r
+\r
+INLINE_INFO            = YES\r
+\r
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen\r
+# will sort the (detailed) documentation of file and class members\r
+# alphabetically by member name. If set to NO the members will appear in\r
+# declaration order.\r
+\r
+SORT_MEMBER_DOCS       = NO\r
+\r
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the\r
+# brief documentation of file, namespace and class members alphabetically\r
+# by member name. If set to NO (the default) the members will appear in\r
+# declaration order.\r
+\r
+SORT_BRIEF_DOCS        = NO\r
+\r
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen\r
+# will sort the (brief and detailed) documentation of class members so that\r
+# constructors and destructors are listed first. If set to NO (the default)\r
+# the constructors will appear in the respective orders defined by\r
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.\r
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO\r
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.\r
+\r
+SORT_MEMBERS_CTORS_1ST = NO\r
+\r
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the\r
+# hierarchy of group names into alphabetical order. If set to NO (the default)\r
+# the group names will appear in their defined order.\r
+\r
+SORT_GROUP_NAMES       = NO\r
+\r
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be\r
+# sorted by fully-qualified names, including namespaces. If set to\r
+# NO (the default), the class list will be sorted only by class name,\r
+# not including the namespace part.\r
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.\r
+# Note: This option applies only to the class list, not to the\r
+# alphabetical list.\r
+\r
+SORT_BY_SCOPE_NAME     = NO\r
+\r
+# The GENERATE_TODOLIST tag can be used to enable (YES) or\r
+# disable (NO) the todo list. This list is created by putting \todo\r
+# commands in the documentation.\r
+\r
+GENERATE_TODOLIST      = YES\r
+\r
+# The GENERATE_TESTLIST tag can be used to enable (YES) or\r
+# disable (NO) the test list. This list is created by putting \test\r
+# commands in the documentation.\r
+\r
+GENERATE_TESTLIST      = YES\r
+\r
+# The GENERATE_BUGLIST tag can be used to enable (YES) or\r
+# disable (NO) the bug list. This list is created by putting \bug\r
+# commands in the documentation.\r
+\r
+GENERATE_BUGLIST       = YES\r
+\r
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or\r
+# disable (NO) the deprecated list. This list is created by putting\r
+# \deprecated commands in the documentation.\r
+\r
+GENERATE_DEPRECATEDLIST= YES\r
+\r
+# The ENABLED_SECTIONS tag can be used to enable conditional\r
+# documentation sections, marked by \if sectionname ... \endif.\r
+\r
+ENABLED_SECTIONS       =\r
+\r
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines\r
+# the initial value of a variable or define consists of for it to appear in\r
+# the documentation. If the initializer consists of more lines than specified\r
+# here it will be hidden. Use a value of 0 to hide initializers completely.\r
+# The appearance of the initializer of individual variables and defines in the\r
+# documentation can be controlled using \showinitializer or \hideinitializer\r
+# command in the documentation regardless of this setting.\r
+\r
+MAX_INITIALIZER_LINES  = 30\r
+\r
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated\r
+# at the bottom of the documentation of classes and structs. If set to YES the\r
+# list will mention the files that were used to generate the documentation.\r
+\r
+SHOW_USED_FILES        = NO\r
+\r
+# If the sources in your project are distributed over multiple directories\r
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy\r
+# in the documentation. The default is NO.\r
+\r
+SHOW_DIRECTORIES       = NO\r
+\r
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.\r
+# This will remove the Files entry from the Quick Index and from the\r
+# Folder Tree View (if specified). The default is YES.\r
+\r
+SHOW_FILES             = YES\r
+\r
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the\r
+# Namespaces page.\r
+# This will remove the Namespaces entry from the Quick Index\r
+# and from the Folder Tree View (if specified). The default is YES.\r
+\r
+SHOW_NAMESPACES        = NO\r
+\r
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that\r
+# doxygen should invoke to get the current version for each file (typically from\r
+# the version control system). Doxygen will invoke the program by executing (via\r
+# popen()) the command <command> <input-file>, where <command> is the value of\r
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file\r
+# provided by doxygen. Whatever the program writes to standard output\r
+# is used as the file version. See the manual for examples.\r
+\r
+FILE_VERSION_FILTER    =\r
+\r
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed\r
+# by doxygen. The layout file controls the global structure of the generated\r
+# output files in an output format independent way. The create the layout file\r
+# that represents doxygen's defaults, run doxygen with the -l option.\r
+# You can optionally specify a file name after the option, if omitted\r
+# DoxygenLayout.xml will be used as the name of the layout file.\r
+\r
+LAYOUT_FILE            =\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to warning and progress messages\r
+#---------------------------------------------------------------------------\r
+\r
+# The QUIET tag can be used to turn on/off the messages that are generated\r
+# by doxygen. Possible values are YES and NO. If left blank NO is used.\r
+\r
+QUIET                  = NO\r
+\r
+# The WARNINGS tag can be used to turn on/off the warning messages that are\r
+# generated by doxygen. Possible values are YES and NO. If left blank\r
+# NO is used.\r
+\r
+WARNINGS               = YES\r
+\r
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings\r
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will\r
+# automatically be disabled.\r
+\r
+WARN_IF_UNDOCUMENTED   = YES\r
+\r
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for\r
+# potential errors in the documentation, such as not documenting some\r
+# parameters in a documented function, or documenting parameters that\r
+# don't exist or using markup commands wrongly.\r
+\r
+WARN_IF_DOC_ERROR      = YES\r
+\r
+# This WARN_NO_PARAMDOC option can be abled to get warnings for\r
+# functions that are documented, but have no documentation for their parameters\r
+# or return value. If set to NO (the default) doxygen will only warn about\r
+# wrong or incomplete parameter documentation, but not about the absence of\r
+# documentation.\r
+\r
+WARN_NO_PARAMDOC       = NO\r
+\r
+# The WARN_FORMAT tag determines the format of the warning messages that\r
+# doxygen can produce. The string should contain the $file, $line, and $text\r
+# tags, which will be replaced by the file and line number from which the\r
+# warning originated and the warning text. Optionally the format may contain\r
+# $version, which will be replaced by the version of the file (if it could\r
+# be obtained via FILE_VERSION_FILTER)\r
+\r
+WARN_FORMAT            = "$file:$line: $text"\r
+\r
+# The WARN_LOGFILE tag can be used to specify a file to which warning\r
+# and error messages should be written. If left blank the output is written\r
+# to stderr.\r
+\r
+WARN_LOGFILE           =\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the input files\r
+#---------------------------------------------------------------------------\r
+\r
+# The INPUT tag can be used to specify the files and/or directories that contain\r
+# documented source files. You may enter file names like "myfile.cpp" or\r
+# directories like "/usr/src/myproject". Separate the files or directories\r
+# with spaces.\r
+\r
+INPUT                  = @top_srcdir@/src/lib eio.dox\r
+\r
+# This tag can be used to specify the character encoding of the source files\r
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is\r
+# also the default input encoding. Doxygen uses libiconv (or the iconv built\r
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for\r
+# the list of possible encodings.\r
+\r
+INPUT_ENCODING         = UTF-8\r
+\r
+# If the value of the INPUT tag contains directories, you can use the\r
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\r
+# and *.h) to filter out the source-files in the directories. If left\r
+# blank the following patterns are tested:\r
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx\r
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90\r
+\r
+FILE_PATTERNS          = *.c *.h\r
+\r
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories\r
+# should be searched for input files as well. Possible values are YES and NO.\r
+# If left blank NO is used.\r
+\r
+RECURSIVE              = YES\r
+\r
+# The EXCLUDE tag can be used to specify files and/or directories that should\r
+# excluded from the INPUT source files. This way you can easily exclude a\r
+# subdirectory from a directory tree whose root is specified with the INPUT tag.\r
+\r
+EXCLUDE                = ../src/lib/eio_private.h\r
+\r
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or\r
+# directories that are symbolic links (a Unix filesystem feature) are excluded\r
+# from the input.\r
+\r
+EXCLUDE_SYMLINKS       = NO\r
+\r
+# If the value of the INPUT tag contains directories, you can use the\r
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude\r
+# certain files from those directories. Note that the wildcards are matched\r
+# against the file with absolute path, so to exclude all test directories\r
+# for example use the pattern */test/*\r
+\r
+EXCLUDE_PATTERNS       =\r
+\r
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names\r
+# (namespaces, classes, functions, etc.) that should be excluded from the\r
+# output. The symbol name can be a fully qualified name, a word, or if the\r
+# wildcard * is used, a substring. Examples: ANamespace, AClass,\r
+# AClass::ANamespace, ANamespace::*Test\r
+\r
+EXCLUDE_SYMBOLS        =\r
+\r
+# The EXAMPLE_PATH tag can be used to specify one or more files or\r
+# directories that contain example code fragments that are included (see\r
+# the \include command).\r
+\r
+EXAMPLE_PATH           =\r
+\r
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the\r
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp\r
+# and *.h) to filter out the source-files in the directories. If left\r
+# blank all files are included.\r
+\r
+EXAMPLE_PATTERNS       =\r
+\r
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be\r
+# searched for input files to be used with the \include or \dontinclude\r
+# commands irrespective of the value of the RECURSIVE tag.\r
+# Possible values are YES and NO. If left blank NO is used.\r
+\r
+EXAMPLE_RECURSIVE      = NO\r
+\r
+# The IMAGE_PATH tag can be used to specify one or more files or\r
+# directories that contain image that are included in the documentation (see\r
+# the \image command).\r
+\r
+IMAGE_PATH             = img\r
+\r
+# The INPUT_FILTER tag can be used to specify a program that doxygen should\r
+# invoke to filter for each input file. Doxygen will invoke the filter program\r
+# by executing (via popen()) the command <filter> <input-file>, where <filter>\r
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an\r
+# input file. Doxygen will then use the output that the filter program writes\r
+# to standard output.\r
+# If FILTER_PATTERNS is specified, this tag will be\r
+# ignored.\r
+\r
+INPUT_FILTER           =\r
+\r
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern\r
+# basis.\r
+# Doxygen will compare the file name with each pattern and apply the\r
+# filter if there is a match.\r
+# The filters are a list of the form:\r
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further\r
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER\r
+# is applied to all files.\r
+\r
+FILTER_PATTERNS        =\r
+\r
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using\r
+# INPUT_FILTER) will be used to filter the input files when producing source\r
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).\r
+\r
+FILTER_SOURCE_FILES    = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to source browsing\r
+#---------------------------------------------------------------------------\r
+\r
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will\r
+# be generated. Documented entities will be cross-referenced with these sources.\r
+# Note: To get rid of all source code in the generated output, make sure also\r
+# VERBATIM_HEADERS is set to NO.\r
+\r
+SOURCE_BROWSER         = NO\r
+\r
+# Setting the INLINE_SOURCES tag to YES will include the body\r
+# of functions and classes directly in the documentation.\r
+\r
+INLINE_SOURCES         = NO\r
+\r
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct\r
+# doxygen to hide any special comment blocks from generated source code\r
+# fragments. Normal C and C++ comments will always remain visible.\r
+\r
+STRIP_CODE_COMMENTS    = YES\r
+\r
+# If the REFERENCED_BY_RELATION tag is set to YES\r
+# then for each documented function all documented\r
+# functions referencing it will be listed.\r
+\r
+REFERENCED_BY_RELATION = NO\r
+\r
+# If the REFERENCES_RELATION tag is set to YES\r
+# then for each documented function all documented entities\r
+# called/used by that function will be listed.\r
+\r
+REFERENCES_RELATION    = NO\r
+\r
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)\r
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from\r
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will\r
+# link to the source code.\r
+# Otherwise they will link to the documentation.\r
+\r
+REFERENCES_LINK_SOURCE = YES\r
+\r
+# If the USE_HTAGS tag is set to YES then the references to source code\r
+# will point to the HTML generated by the htags(1) tool instead of doxygen\r
+# built-in source browser. The htags tool is part of GNU's global source\r
+# tagging system (see http://www.gnu.org/software/global/global.html). You\r
+# will need version 4.8.6 or higher.\r
+\r
+USE_HTAGS              = NO\r
+\r
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen\r
+# will generate a verbatim copy of the header file for each class for\r
+# which an include is specified. Set to NO to disable this.\r
+\r
+VERBATIM_HEADERS       = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the alphabetical class index\r
+#---------------------------------------------------------------------------\r
+\r
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index\r
+# of all compounds will be generated. Enable this if the project\r
+# contains a lot of classes, structs, unions or interfaces.\r
+\r
+ALPHABETICAL_INDEX     = YES\r
+\r
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then\r
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns\r
+# in which this list will be split (can be a number in the range [1..20])\r
+\r
+COLS_IN_ALPHA_INDEX    = 5\r
+\r
+# In case all classes in a project start with a common prefix, all\r
+# classes will be put under the same header in the alphabetical index.\r
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that\r
+# should be ignored while generating the index headers.\r
+\r
+IGNORE_PREFIX          =\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the HTML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will\r
+# generate HTML output.\r
+\r
+GENERATE_HTML          = YES\r
+\r
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.\r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be\r
+# put in front of it. If left blank `html' will be used as the default path.\r
+\r
+HTML_OUTPUT            = html\r
+\r
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for\r
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank\r
+# doxygen will generate files with .html extension.\r
+\r
+HTML_FILE_EXTENSION    = .html\r
+\r
+# The HTML_HEADER tag can be used to specify a personal HTML header for\r
+# each generated HTML page. If it is left blank doxygen will generate a\r
+# standard header.\r
+\r
+HTML_HEADER            = @srcdir@/head.html\r
+\r
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for\r
+# each generated HTML page. If it is left blank doxygen will generate a\r
+# standard footer.\r
+\r
+HTML_FOOTER            = @srcdir@/foot.html\r
+\r
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading\r
+# style sheet that is used by each HTML page. It can be used to\r
+# fine-tune the look of the HTML output. If the tag is left blank doxygen\r
+# will generate a default style sheet. Note that doxygen will try to copy\r
+# the style sheet file to the HTML output directory, so don't put your own\r
+# stylesheet in the HTML output directory as well, or it will be erased!\r
+\r
+HTML_STYLESHEET        = @srcdir@/e.css\r
+\r
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.\r
+# Doxygen will adjust the colors in the stylesheet and background images\r
+# according to this color. Hue is specified as an angle on a colorwheel,\r
+# see http://en.wikipedia.org/wiki/Hue for more information.\r
+# For instance the value 0 represents red, 60 is yellow, 120 is green,\r
+# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.\r
+# The allowed range is 0 to 359.\r
+\r
+HTML_COLORSTYLE_HUE    = 220\r
+\r
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of\r
+# the colors in the HTML output. For a value of 0 the output will use\r
+# grayscales only. A value of 255 will produce the most vivid colors.\r
+\r
+HTML_COLORSTYLE_SAT    = 100\r
+\r
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to\r
+# the luminance component of the colors in the HTML output. Values below\r
+# 100 gradually make the output lighter, whereas values above 100 make\r
+# the output darker. The value divided by 100 is the actual gamma applied,\r
+# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,\r
+# and 100 does not change the gamma.\r
+\r
+HTML_COLORSTYLE_GAMMA  = 80\r
+\r
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML\r
+# page will contain the date and time when the page was generated. Setting\r
+# this to NO can help when comparing the output of multiple runs.\r
+\r
+HTML_TIMESTAMP         = YES\r
+\r
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,\r
+# files or namespaces will be aligned in HTML using tables. If set to\r
+# NO a bullet list will be used.\r
+\r
+HTML_ALIGN_MEMBERS     = YES\r
+\r
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML\r
+# documentation will contain sections that can be hidden and shown after the\r
+# page has loaded. For this to work a browser that supports\r
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox\r
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).\r
+\r
+HTML_DYNAMIC_SECTIONS  = NO\r
+\r
+# If the GENERATE_DOCSET tag is set to YES, additional index files\r
+# will be generated that can be used as input for Apple's Xcode 3\r
+# integrated development environment, introduced with OSX 10.5 (Leopard).\r
+# To create a documentation set, doxygen will generate a Makefile in the\r
+# HTML output directory. Running make will produce the docset in that\r
+# directory and running "make install" will install the docset in\r
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find\r
+# it at startup.\r
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html\r
+# for more information.\r
+\r
+GENERATE_DOCSET        = NO\r
+\r
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the\r
+# feed. A documentation feed provides an umbrella under which multiple\r
+# documentation sets from a single provider (such as a company or product suite)\r
+# can be grouped.\r
+\r
+DOCSET_FEEDNAME        = "Doxygen generated docs"\r
+\r
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that\r
+# should uniquely identify the documentation set bundle. This should be a\r
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen\r
+# will append .docset to the name.\r
+\r
+DOCSET_BUNDLE_ID       = org.doxygen.Project\r
+\r
+# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify\r
+# the documentation publisher. This should be a reverse domain-name style\r
+# string, e.g. com.mycompany.MyDocSet.documentation.\r
+\r
+DOCSET_PUBLISHER_ID    = org.doxygen.Publisher\r
+\r
+# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.\r
+\r
+DOCSET_PUBLISHER_NAME  = Publisher\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files\r
+# will be generated that can be used as input for tools like the\r
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)\r
+# of the generated HTML documentation.\r
+\r
+GENERATE_HTMLHELP      = NO\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can\r
+# be used to specify the file name of the resulting .chm file. You\r
+# can add a path in front of the file if the result should not be\r
+# written to the html output directory.\r
+\r
+CHM_FILE               =\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can\r
+# be used to specify the location (absolute path including file name) of\r
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run\r
+# the HTML help compiler on the generated index.hhp.\r
+\r
+HHC_LOCATION           =\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag\r
+# controls if a separate .chi index file is generated (YES) or that\r
+# it should be included in the master .chm file (NO).\r
+\r
+GENERATE_CHI           = NO\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING\r
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file\r
+# content.\r
+\r
+CHM_INDEX_ENCODING     =\r
+\r
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag\r
+# controls whether a binary table of contents is generated (YES) or a\r
+# normal table of contents (NO) in the .chm file.\r
+\r
+BINARY_TOC             = NO\r
+\r
+# The TOC_EXPAND flag can be set to YES to add extra items for group members\r
+# to the contents of the HTML help documentation and to the tree view.\r
+\r
+TOC_EXPAND             = NO\r
+\r
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and\r
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated\r
+# that can be used as input for Qt's qhelpgenerator to generate a\r
+# Qt Compressed Help (.qch) of the generated HTML documentation.\r
+\r
+GENERATE_QHP           = NO\r
+\r
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can\r
+# be used to specify the file name of the resulting .qch file.\r
+# The path specified is relative to the HTML output folder.\r
+\r
+QCH_FILE               =\r
+\r
+# The QHP_NAMESPACE tag specifies the namespace to use when generating\r
+# Qt Help Project output. For more information please see\r
+# http://doc.trolltech.com/qthelpproject.html#namespace\r
+\r
+QHP_NAMESPACE          = org.doxygen.Project\r
+\r
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating\r
+# Qt Help Project output. For more information please see\r
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders\r
+\r
+QHP_VIRTUAL_FOLDER     = doc\r
+\r
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to\r
+# add. For more information please see\r
+# http://doc.trolltech.com/qthelpproject.html#custom-filters\r
+\r
+QHP_CUST_FILTER_NAME   =\r
+\r
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the\r
+# custom filter to add. For more information please see\r
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">\r
+# Qt Help Project / Custom Filters</a>.\r
+\r
+QHP_CUST_FILTER_ATTRS  =\r
+\r
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this\r
+# project's\r
+# filter section matches.\r
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">\r
+# Qt Help Project / Filter Attributes</a>.\r
+\r
+QHP_SECT_FILTER_ATTRS  =\r
+\r
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can\r
+# be used to specify the location of Qt's qhelpgenerator.\r
+# If non-empty doxygen will try to run qhelpgenerator on the generated\r
+# .qhp file.\r
+\r
+QHG_LOCATION           =\r
+\r
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files\r
+#  will be generated, which together with the HTML files, form an Eclipse help\r
+# plugin. To install this plugin and make it available under the help contents\r
+# menu in Eclipse, the contents of the directory containing the HTML and XML\r
+# files needs to be copied into the plugins directory of eclipse. The name of\r
+# the directory within the plugins directory should be the same as\r
+# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before\r
+# the help appears.\r
+\r
+GENERATE_ECLIPSEHELP   = NO\r
+\r
+# A unique identifier for the eclipse help plugin. When installing the plugin\r
+# the directory name containing the HTML and XML files should also have\r
+# this name.\r
+\r
+ECLIPSE_DOC_ID         = org.doxygen.Project\r
+\r
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at\r
+# top of each HTML page. The value NO (the default) enables the index and\r
+# the value YES disables it.\r
+\r
+DISABLE_INDEX          = YES\r
+\r
+# This tag can be used to set the number of enum values (range [1..20])\r
+# that doxygen will group on one line in the generated HTML documentation.\r
+\r
+ENUM_VALUES_PER_LINE   = 4\r
+\r
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index\r
+# structure should be generated to display hierarchical information.\r
+# If the tag value is set to YES, a side panel will be generated\r
+# containing a tree-like index structure (just like the one that\r
+# is generated for HTML Help). For this to work a browser that supports\r
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).\r
+# Windows users are probably better off using the HTML help feature.\r
+\r
+GENERATE_TREEVIEW      = NO\r
+\r
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,\r
+# and Class Hierarchy pages using a tree view instead of an ordered list.\r
+\r
+USE_INLINE_TREES       = NO\r
+\r
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be\r
+# used to set the initial width (in pixels) of the frame in which the tree\r
+# is shown.\r
+\r
+TREEVIEW_WIDTH         = 250\r
+\r
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open\r
+# links to external symbols imported via tag files in a separate window.\r
+\r
+EXT_LINKS_IN_WINDOW    = NO\r
+\r
+# Use this tag to change the font size of Latex formulas included\r
+# as images in the HTML documentation. The default is 10. Note that\r
+# when you change the font size after a successful doxygen run you need\r
+# to manually remove any form_*.png images from the HTML output directory\r
+# to force them to be regenerated.\r
+\r
+FORMULA_FONTSIZE       = 10\r
+\r
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images\r
+# generated for formulas are transparent PNGs. Transparent PNGs are\r
+# not supported properly for IE 6.0, but are supported on all modern browsers.\r
+# Note that when changing this option you need to delete any form_*.png files\r
+# in the HTML output before the changes have effect.\r
+\r
+FORMULA_TRANSPARENT    = YES\r
+\r
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box\r
+# for the HTML output. The underlying search engine uses javascript\r
+# and DHTML and should work on any modern browser. Note that when using\r
+# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets\r
+# (GENERATE_DOCSET) there is already a search function so this one should\r
+# typically be disabled. For large projects the javascript based search engine\r
+# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.\r
+\r
+SEARCHENGINE           = NO\r
+\r
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be\r
+# implemented using a PHP enabled web server instead of at the web client\r
+# using Javascript. Doxygen will generate the search PHP script and index\r
+# file to put on the web server. The advantage of the server\r
+# based approach is that it scales better to large projects and allows\r
+# full text search. The disadvances is that it is more difficult to setup\r
+# and does not have live searching capabilities.\r
+\r
+SERVER_BASED_SEARCH    = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the LaTeX output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will\r
+# generate Latex output.\r
+\r
+GENERATE_LATEX         = YES\r
+\r
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.\r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be\r
+# put in front of it. If left blank `latex' will be used as the default path.\r
+\r
+LATEX_OUTPUT           = latex\r
+\r
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be\r
+# invoked. If left blank `latex' will be used as the default command name.\r
+# Note that when enabling USE_PDFLATEX this option is only used for\r
+# generating bitmaps for formulas in the HTML output, but not in the\r
+# Makefile that is written to the output directory.\r
+\r
+LATEX_CMD_NAME         = latex\r
+\r
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to\r
+# generate index for LaTeX. If left blank `makeindex' will be used as the\r
+# default command name.\r
+\r
+MAKEINDEX_CMD_NAME     = makeindex\r
+\r
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact\r
+# LaTeX documents. This may be useful for small projects and may help to\r
+# save some trees in general.\r
+\r
+COMPACT_LATEX          = NO\r
+\r
+# The PAPER_TYPE tag can be used to set the paper type that is used\r
+# by the printer. Possible values are: a4, a4wide, letter, legal and\r
+# executive. If left blank a4wide will be used.\r
+\r
+PAPER_TYPE             = a4wide\r
+\r
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX\r
+# packages that should be included in the LaTeX output.\r
+\r
+EXTRA_PACKAGES         =\r
+\r
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for\r
+# the generated latex document. The header should contain everything until\r
+# the first chapter. If it is left blank doxygen will generate a\r
+# standard header. Notice: only use this tag if you know what you are doing!\r
+\r
+LATEX_HEADER           =\r
+\r
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated\r
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will\r
+# contain links (just like the HTML output) instead of page references\r
+# This makes the output suitable for online browsing using a pdf viewer.\r
+\r
+PDF_HYPERLINKS         = YES\r
+\r
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of\r
+# plain latex in the generated Makefile. Set this option to YES to get a\r
+# higher quality PDF documentation.\r
+\r
+USE_PDFLATEX           = YES\r
+\r
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.\r
+# command to the generated LaTeX files. This will instruct LaTeX to keep\r
+# running if errors occur, instead of asking the user for help.\r
+# This option is also used when generating formulas in HTML.\r
+\r
+LATEX_BATCHMODE        = NO\r
+\r
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not\r
+# include the index chapters (such as File Index, Compound Index, etc.)\r
+# in the output.\r
+\r
+LATEX_HIDE_INDICES     = NO\r
+\r
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include\r
+# source code with syntax highlighting in the LaTeX output.\r
+# Note that which sources are shown also depends on other settings\r
+# such as SOURCE_BROWSER.\r
+\r
+LATEX_SOURCE_CODE      = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the RTF output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output\r
+# The RTF output is optimized for Word 97 and may not look very pretty with\r
+# other RTF readers or editors.\r
+\r
+GENERATE_RTF           = NO\r
+\r
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.\r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be\r
+# put in front of it. If left blank `rtf' will be used as the default path.\r
+\r
+RTF_OUTPUT             = rtf\r
+\r
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact\r
+# RTF documents. This may be useful for small projects and may help to\r
+# save some trees in general.\r
+\r
+COMPACT_RTF            = NO\r
+\r
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated\r
+# will contain hyperlink fields. The RTF file will\r
+# contain links (just like the HTML output) instead of page references.\r
+# This makes the output suitable for online browsing using WORD or other\r
+# programs which support those fields.\r
+# Note: wordpad (write) and others do not support links.\r
+\r
+RTF_HYPERLINKS         = NO\r
+\r
+# Load stylesheet definitions from file. Syntax is similar to doxygen's\r
+# config file, i.e. a series of assignments. You only have to provide\r
+# replacements, missing definitions are set to their default value.\r
+\r
+RTF_STYLESHEET_FILE    =\r
+\r
+# Set optional variables used in the generation of an rtf document.\r
+# Syntax is similar to doxygen's config file.\r
+\r
+RTF_EXTENSIONS_FILE    =\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the man page output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will\r
+# generate man pages\r
+\r
+GENERATE_MAN           = YES\r
+\r
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.\r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be\r
+# put in front of it. If left blank `man' will be used as the default path.\r
+\r
+MAN_OUTPUT             = man\r
+\r
+# The MAN_EXTENSION tag determines the extension that is added to\r
+# the generated man pages (default is the subroutine's section .3)\r
+\r
+MAN_EXTENSION          = .3\r
+\r
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,\r
+# then it will generate one additional man file for each entity\r
+# documented in the real man page(s). These additional files\r
+# only source the real man page, but without them the man command\r
+# would be unable to find the correct page. The default is NO.\r
+\r
+MAN_LINKS              = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the XML output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_XML tag is set to YES Doxygen will\r
+# generate an XML file that captures the structure of\r
+# the code including all documentation.\r
+\r
+GENERATE_XML           = NO\r
+\r
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.\r
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be\r
+# put in front of it. If left blank `xml' will be used as the default path.\r
+\r
+XML_OUTPUT             = xml\r
+\r
+# The XML_SCHEMA tag can be used to specify an XML schema,\r
+# which can be used by a validating XML parser to check the\r
+# syntax of the XML files.\r
+\r
+XML_SCHEMA             =\r
+\r
+# The XML_DTD tag can be used to specify an XML DTD,\r
+# which can be used by a validating XML parser to check the\r
+# syntax of the XML files.\r
+\r
+XML_DTD                =\r
+\r
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will\r
+# dump the program listings (including syntax highlighting\r
+# and cross-referencing information) to the XML output. Note that\r
+# enabling this will significantly increase the size of the XML output.\r
+\r
+XML_PROGRAMLISTING     = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options for the AutoGen Definitions output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will\r
+# generate an AutoGen Definitions (see autogen.sf.net) file\r
+# that captures the structure of the code including all\r
+# documentation. Note that this feature is still experimental\r
+# and incomplete at the moment.\r
+\r
+GENERATE_AUTOGEN_DEF   = NO\r
+\r
+#---------------------------------------------------------------------------\r
+# configuration options related to the Perl module output\r
+#---------------------------------------------------------------------------\r
+\r
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will\r
+# generate a Perl module file that captures the structure of\r
+# the code including all documentation. Note that this\r
+# feature is still experimental and incomplete at the\r
+# moment.\r
+\r
+GENERATE_PERLMOD       = NO\r
+\r
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate\r
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able\r
+# to generate PDF and DVI output from the Perl module output.\r
+\r
+PERLMOD_LATEX          = NO\r
+\r
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be\r
+# nicely formatted so it can be parsed by a human reader.\r
+# This is useful\r
+# if you want to understand what is going on.\r
+# On the other hand, if this\r
+# tag is set to NO the size of the Perl module output will be much smaller\r
+# and Perl will parse it just the same.\r
+\r
+PERLMOD_PRETTY         = YES\r
+\r
+# The names of the make variables in the generated doxyrules.make file\r
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.\r
+# This is useful so different doxyrules.make files included by the same\r
+# Makefile don't overwrite each other's variables.\r
+\r
+PERLMOD_MAKEVAR_PREFIX =\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the preprocessor\r
+#---------------------------------------------------------------------------\r
+\r
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will\r
+# evaluate all C-preprocessor directives found in the sources and include\r
+# files.\r
+\r
+ENABLE_PREPROCESSING   = YES\r
+\r
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro\r
+# names in the source code. If set to NO (the default) only conditional\r
+# compilation will be performed. Macro expansion can be done in a controlled\r
+# way by setting EXPAND_ONLY_PREDEF to YES.\r
+\r
+MACRO_EXPANSION        = NO\r
+\r
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES\r
+# then the macro expansion is limited to the macros specified with the\r
+# PREDEFINED and EXPAND_AS_DEFINED tags.\r
+\r
+EXPAND_ONLY_PREDEF     = NO\r
+\r
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files\r
+# in the INCLUDE_PATH (see below) will be search if a #include is found.\r
+\r
+SEARCH_INCLUDES        = YES\r
+\r
+# The INCLUDE_PATH tag can be used to specify one or more directories that\r
+# contain include files that are not input files but should be processed by\r
+# the preprocessor.\r
+\r
+INCLUDE_PATH           =\r
+\r
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard\r
+# patterns (like *.h and *.hpp) to filter out the header-files in the\r
+# directories. If left blank, the patterns specified with FILE_PATTERNS will\r
+# be used.\r
+\r
+INCLUDE_FILE_PATTERNS  =\r
+\r
+# The PREDEFINED tag can be used to specify one or more macro names that\r
+# are defined before the preprocessor is started (similar to the -D option of\r
+# gcc). The argument of the tag is a list of macros of the form: name\r
+# or name=definition (no spaces). If the definition and the = are\r
+# omitted =1 is assumed. To prevent a macro definition from being\r
+# undefined via #undef or recursively expanded use the := operator\r
+# instead of the = operator.\r
+\r
+PREDEFINED             =\r
+\r
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then\r
+# this tag can be used to specify a list of macro names that should be expanded.\r
+# The macro definition that is found in the sources will be used.\r
+# Use the PREDEFINED tag if you want to use a different macro definition.\r
+\r
+EXPAND_AS_DEFINED      =\r
+\r
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then\r
+# doxygen's preprocessor will remove all function-like macros that are alone\r
+# on a line, have an all uppercase name, and do not end with a semicolon. Such\r
+# function macros are typically used for boiler-plate code, and will confuse\r
+# the parser if not removed.\r
+\r
+SKIP_FUNCTION_MACROS   = YES\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration::additions related to external references\r
+#---------------------------------------------------------------------------\r
+\r
+# The TAGFILES option can be used to specify one or more tagfiles.\r
+# Optionally an initial location of the external documentation\r
+# can be added for each tagfile. The format of a tag file without\r
+# this location is as follows:\r
+#\r
+# TAGFILES = file1 file2 ...\r
+# Adding location for the tag files is done as follows:\r
+#\r
+# TAGFILES = file1=loc1 "file2 = loc2" ...\r
+# where "loc1" and "loc2" can be relative or absolute paths or\r
+# URLs. If a location is present for each tag, the installdox tool\r
+# does not have to be run to correct the links.\r
+# Note that each tag file must have a unique name\r
+# (where the name does NOT include the path)\r
+# If a tag file is not located in the directory in which doxygen\r
+# is run, you must also specify the path to the tagfile here.\r
+\r
+TAGFILES               =\r
+\r
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create\r
+# a tag file that is based on the input files it reads.\r
+\r
+GENERATE_TAGFILE       =\r
+\r
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed\r
+# in the class index. If set to NO only the inherited external classes\r
+# will be listed.\r
+\r
+ALLEXTERNALS           = NO\r
+\r
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed\r
+# in the modules index. If set to NO, only the current project's groups will\r
+# be listed.\r
+\r
+EXTERNAL_GROUPS        = YES\r
+\r
+# The PERL_PATH should be the absolute path and name of the perl script\r
+# interpreter (i.e. the result of `which perl').\r
+\r
+PERL_PATH              = /usr/bin/perl\r
+\r
+#---------------------------------------------------------------------------\r
+# Configuration options related to the dot tool\r
+#---------------------------------------------------------------------------\r
+\r
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will\r
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base\r
+# or super classes. Setting the tag to NO turns the diagrams off. Note that\r
+# this option is superseded by the HAVE_DOT option below. This is only a\r
+# fallback. It is recommended to install and use dot, since it yields more\r
+# powerful graphs.\r
+\r
+CLASS_DIAGRAMS         = YES\r
+\r
+# You can define message sequence charts within doxygen comments using the \msc\r
+# command. Doxygen will then run the mscgen tool (see\r
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the\r
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where\r
+# the mscgen tool resides. If left empty the tool is assumed to be found in the\r
+# default search path.\r
+\r
+MSCGEN_PATH            =\r
+\r
+# If set to YES, the inheritance and collaboration graphs will hide\r
+# inheritance and usage relations if the target is undocumented\r
+# or is not a class.\r
+\r
+HIDE_UNDOC_RELATIONS   = YES\r
+\r
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is\r
+# available from the path. This tool is part of Graphviz, a graph visualization\r
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section\r
+# have no effect if this option is set to NO (the default)\r
+\r
+HAVE_DOT               = NO\r
+\r
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is\r
+# allowed to run in parallel. When set to 0 (the default) doxygen will\r
+# base this on the number of processors available in the system. You can set it\r
+# explicitly to a value larger than 0 to get control over the balance\r
+# between CPU load and processing speed.\r
+\r
+DOT_NUM_THREADS        = 0\r
+\r
+# By default doxygen will write a font called FreeSans.ttf to the output\r
+# directory and reference it in all dot files that doxygen generates. This\r
+# font does not include all possible unicode characters however, so when you need\r
+# these (or just want a differently looking font) you can specify the font name\r
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,\r
+# which can be done by putting it in a standard location or by setting the\r
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory\r
+# containing the font.\r
+\r
+DOT_FONTNAME           = FreeSans.ttf\r
+\r
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.\r
+# The default size is 10pt.\r
+\r
+DOT_FONTSIZE           = 10\r
+\r
+# By default doxygen will tell dot to use the output directory to look for the\r
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a\r
+# different font using DOT_FONTNAME you can set the path where dot\r
+# can find it using this tag.\r
+\r
+DOT_FONTPATH           =\r
+\r
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen\r
+# will generate a graph for each documented class showing the direct and\r
+# indirect inheritance relations. Setting this tag to YES will force the\r
+# the CLASS_DIAGRAMS tag to NO.\r
+\r
+CLASS_GRAPH            = YES\r
+\r
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen\r
+# will generate a graph for each documented class showing the direct and\r
+# indirect implementation dependencies (inheritance, containment, and\r
+# class references variables) of the class with other documented classes.\r
+\r
+COLLABORATION_GRAPH    = YES\r
+\r
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen\r
+# will generate a graph for groups, showing the direct groups dependencies\r
+\r
+GROUP_GRAPHS           = YES\r
+\r
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and\r
+# collaboration diagrams in a style similar to the OMG's Unified Modeling\r
+# Language.\r
+\r
+UML_LOOK               = NO\r
+\r
+# If set to YES, the inheritance and collaboration graphs will show the\r
+# relations between templates and their instances.\r
+\r
+TEMPLATE_RELATIONS     = NO\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT\r
+# tags are set to YES then doxygen will generate a graph for each documented\r
+# file showing the direct and indirect include dependencies of the file with\r
+# other documented files.\r
+\r
+INCLUDE_GRAPH          = YES\r
+\r
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and\r
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each\r
+# documented header file showing the documented files that directly or\r
+# indirectly include this file.\r
+\r
+INCLUDED_BY_GRAPH      = YES\r
+\r
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then\r
+# doxygen will generate a call dependency graph for every global function\r
+# or class method. Note that enabling this option will significantly increase\r
+# the time of a run. So in most cases it will be better to enable call graphs\r
+# for selected functions only using the \callgraph command.\r
+\r
+CALL_GRAPH             = NO\r
+\r
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then\r
+# doxygen will generate a caller dependency graph for every global function\r
+# or class method. Note that enabling this option will significantly increase\r
+# the time of a run. So in most cases it will be better to enable caller\r
+# graphs for selected functions only using the \callergraph command.\r
+\r
+CALLER_GRAPH           = NO\r
+\r
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen\r
+# will graphical hierarchy of all classes instead of a textual one.\r
+\r
+GRAPHICAL_HIERARCHY    = YES\r
+\r
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES\r
+# then doxygen will show the dependencies a directory has on other directories\r
+# in a graphical way. The dependency relations are determined by the #include\r
+# relations between the files in the directories.\r
+\r
+DIRECTORY_GRAPH        = YES\r
+\r
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images\r
+# generated by dot. Possible values are png, jpg, or gif\r
+# If left blank png will be used.\r
+\r
+DOT_IMAGE_FORMAT       = png\r
+\r
+# The tag DOT_PATH can be used to specify the path where the dot tool can be\r
+# found. If left blank, it is assumed the dot tool can be found in the path.\r
+\r
+DOT_PATH               =\r
+\r
+# The DOTFILE_DIRS tag can be used to specify one or more directories that\r
+# contain dot files that are included in the documentation (see the\r
+# \dotfile command).\r
+\r
+DOTFILE_DIRS           =\r
+\r
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of\r
+# nodes that will be shown in the graph. If the number of nodes in a graph\r
+# becomes larger than this value, doxygen will truncate the graph, which is\r
+# visualized by representing a node as a red box. Note that doxygen if the\r
+# number of direct children of the root node in a graph is already larger than\r
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note\r
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.\r
+\r
+DOT_GRAPH_MAX_NODES    = 50\r
+\r
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the\r
+# graphs generated by dot. A depth value of 3 means that only nodes reachable\r
+# from the root by following a path via at most 3 edges will be shown. Nodes\r
+# that lay further from the root node will be omitted. Note that setting this\r
+# option to 1 or 2 may greatly reduce the computation time needed for large\r
+# code bases. Also note that the size of a graph can be further restricted by\r
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.\r
+\r
+MAX_DOT_GRAPH_DEPTH    = 0\r
+\r
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent\r
+# background. This is disabled by default, because dot on Windows does not\r
+# seem to support this out of the box. Warning: Depending on the platform used,\r
+# enabling this option may lead to badly anti-aliased labels on the edges of\r
+# a graph (i.e. they become hard to read).\r
+\r
+DOT_TRANSPARENT        = NO\r
+\r
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output\r
+# files in one run (i.e. multiple -o and -T options on the command line). This\r
+# makes dot run faster, but since only newer versions of dot (>1.8.10)\r
+# support this, this feature is disabled by default.\r
+\r
+DOT_MULTI_TARGETS      = NO\r
+\r
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will\r
+# generate a legend page explaining the meaning of the various boxes and\r
+# arrows in the dot generated graphs.\r
+\r
+GENERATE_LEGEND        = YES\r
+\r
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will\r
+# remove the intermediate dot files that are used to generate\r
+# the various graphs.\r
+\r
+DOT_CLEANUP            = YES\r
diff --git a/doc/Makefile.am b/doc/Makefile.am
new file mode 100644 (file)
index 0000000..fcf2a28
--- /dev/null
@@ -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 (file)
index 0000000..8697a3a
--- /dev/null
+++ b/doc/e.css
@@ -0,0 +1,218 @@
+/*
+    Author:
+        Andres Blanc <andresblanc@gmail.com>
+       DaveMDS Andreoli <dave@gurumeditation.it>
+
+    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 (file)
index 0000000..32a97b7
--- /dev/null
@@ -0,0 +1,456 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2010 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *          Stephen "okra" Houston <unixtitan@gmail.com>
+ *           Gustavo Sverzut Barbieri <barbieri@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @mainpage Eio
+ * @author Cedric Bail <cedric.bail@@free.fr>
+ * @author Stephen "okra" Houston <unixtitan@@gmail.com>
+ * @author Gustavo Sverzut Barbieri <barbieri@@gmail.com>
+ * @author Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ * @author Guillaume "kuri" Friloux <guillaume.friloux@@asp64.com>
+ * @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 <Ecore.h>
+ * #include <Eio.h>
+ *
+ * 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 <Ecore.h>
+ * #include <Eio.h>
+ *
+ * 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 <Ecore.h>
+ * #include <Eio.h>
+ *
+ * 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 <Eina.h>
+ * #include <Ecore.h>
+ * #include <Eio.h>
+ *
+ * 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 <Eina.h>
+ * #include <Ecore.h>
+ * #include <Eio.h>
+ *
+ * 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 (file)
index 0000000..78ef911
--- /dev/null
@@ -0,0 +1,19 @@
+ <div id="push"></div>
+ </div> <!-- #content -->
+  </div> <!-- .layout -->
+ </div> <!-- #container -->
+  <div id="footer">
+    <table><tr>
+      <td class="poweredby"><img src="doxygen.png"></td>
+      <td class="copyright">Copyright &copy;$year Enlightenment</td>
+      <td class="generated">Docs generated $datetime</td>
+    </tr></table>
+  </div>
+
+
+</body>
+</html>
diff --git a/doc/head.html b/doc/head.html
new file mode 100644 (file)
index 0000000..b0f0a2c
--- /dev/null
@@ -0,0 +1,67 @@
+<html>
+<head>
+    <title>$title</title>
+    <meta http-equiv="content-type" content="text/html;charset=UTF-8">
+    <meta name="author" content="Andres Blanc" >
+    
+    <link rel="icon" href="img/favicon.png" type="image/x-icon">
+    <link rel="shortcut icon" href="img/favicon.png" type="image/x-icon">
+    <link rel="icon" href="img/favicon.png" type="image/ico">
+    <link rel="shortcut icon" href="img/favicon.png" type="image/ico">
+
+    <link rel="stylesheet" type="text/css" media="screen" href="e.css">
+    <link rel="stylesheet" type="text/css" media="screen" href="edoxy.css">
+</head>
+
+<body>
+
+<div id="container">
+
+<div id="header">
+<div class="layout">
+    
+    <h1><span>Enlightenment</span></h1>
+    <h2><span>Beauty at your fingertips</span></h2>
+
+    <div class="menu-container">
+        <div class="menu">
+            <ul>
+               <li class="current"><a href="http://web.enlightenment.org/p.php?p=docs">Docs</a></li>
+                <li><a href="http://trac.enlightenment.org/e">Tracker</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=contact">Contact</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=contribute">Contribute</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=support">Support</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=download">Download</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=about">About</a></li>
+                <li><a href="http://www.enlightenment.org/p.php?p=news">News</a></li>
+                <li><a href="http://www.enlightenment.org/">Home</a></li>
+            </ul>
+        </div>
+    </div>
+
+    <div class="doxytitle">
+        $projectname Documentation <small>at $date</small>
+    </div>
+
+    <div class="menu-container">
+        <div class="submenu">
+            <ul class="current">
+                <li><a href="pages.html">Tutorials</a></li>
+                <li><a href="group__Eio__Helper.html">Helper API</a></li>
+                <li><a href="group__Eio__Monitor.html">monitoring API</a></li>
+                <li><a href="group__Eio__Xattr.html">eXtended attribute API</a></li>
+                <li><a href="group__Eio__Eet.html">EET API</a></li>
+                <li><a href="group__Eio__Map.html">reading file API</a></li>
+                <li><a href="group__Eio__Group.html">Reference API</a></li>
+               <li class="current"><a  href="index.html">Main Page</a></li>
+            </ul>
+        </div>
+    </div>
+
+
+    <div class="clear"></div>
+</div>
+</div>
+
+<div id="content">
+<div class="layout">
diff --git a/doc/img/e.png b/doc/img/e.png
new file mode 100644 (file)
index 0000000..b3884a5
Binary files /dev/null and b/doc/img/e.png differ
diff --git a/doc/img/edoxy.css b/doc/img/edoxy.css
new file mode 100644 (file)
index 0000000..3caf7a9
--- /dev/null
@@ -0,0 +1,483 @@
+/*
+ * This file contain a custom doxygen style to match e.org graphics
+ */
+
+
+
+/* BODY,H1,H2,H3,H4,H5,H6,P,CENTER,TD,TH,UL,DL,DIV {
+       font-family: Geneva, Arial, Helvetica, sans-serif;
+}*/ 
+BODY, TD {
+       font-size: 12px;
+}
+H1 {
+       text-align: center;
+       font-size: 160%;
+}
+H2 {
+       font-size: 120%;
+}
+H3 {
+       font-size: 100%;
+}
+CAPTION { 
+       font-weight: bold 
+}
+DIV.qindex {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navpath {
+       width: 100%;
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       padding: 2px;
+       line-height: 140%;
+}
+DIV.navtab {
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+TD.navtab {
+       font-size: 70%;
+}
+A.qindex {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D;
+}
+A.qindex:visited {
+       text-decoration: none;
+       font-weight: bold;
+       color: #1A419D
+}
+A.qindex:hover {
+       text-decoration: none;
+       background-color: #ddddff;
+}
+A.qindexHL {
+       text-decoration: none;
+       font-weight: bold;
+       background-color: #6666cc;
+       color: #ffffff;
+       border: 1px double #9295C2;
+}
+A.qindexHL:hover {
+       text-decoration: none;
+       background-color: #6666cc;
+       color: #ffffff;
+}
+A.qindexHL:visited { 
+       text-decoration: none; 
+       background-color: #6666cc; 
+       color: #ffffff 
+}
+A.el { 
+       text-decoration: none; 
+       font-weight: bold 
+}
+A.elRef { 
+       font-weight: bold 
+}
+A.code:link { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.code:visited { 
+       text-decoration: none; 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:link { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A.codeRef:visited { 
+       font-weight: normal; 
+       color: #0000FF
+}
+A:hover, A:visited:hover { 
+       text-decoration: none;  
+       /* background-color: #f2f2ff; */
+       color: #000055;
+}
+A.anchor {
+       color: #000;
+}
+DL.el { 
+       margin-left: -1cm 
+}
+.fragment {
+       font-family: monospace, fixed;
+       font-size: 95%;
+}
+PRE.fragment {
+       border: 1px solid #CCCCCC;
+       background-color: #f5f5f5;
+       margin-top: 4px;
+       margin-bottom: 4px;
+       margin-left: 2px;
+       margin-right: 8px;
+       padding-left: 6px;
+       padding-right: 6px;
+       padding-top: 4px;
+       padding-bottom: 4px;
+}
+DIV.ah { 
+       background-color: black; 
+       font-weight: bold; 
+       color: #ffffff; 
+       margin-bottom: 3px; 
+       margin-top: 3px 
+}
+
+DIV.groupHeader {
+       margin-left: 16px;
+       margin-top: 12px;
+       margin-bottom: 6px;
+       font-weight: bold;
+}
+DIV.groupText { 
+       margin-left: 16px; 
+       font-style: italic; 
+       font-size: 90% 
+}
+/*BODY {
+       background: white;
+       color: black;
+       margin-right: 20px;
+       margin-left: 20px;
+}*/
+TD.indexkey {
+       background-color: #e8eef2;
+       font-weight: bold;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TD.indexvalue {
+       background-color: #e8eef2;
+       font-style: italic;
+       padding-right  : 10px;
+       padding-top    : 2px;
+       padding-left   : 10px;
+       padding-bottom : 2px;
+       margin-left    : 0px;
+       margin-right   : 0px;
+       margin-top     : 2px;
+       margin-bottom  : 2px;
+       border: 1px solid #CCCCCC;
+}
+TR.memlist {
+       background-color: #f0f0f0; 
+}
+P.formulaDsp { 
+       text-align: center; 
+}
+IMG.formulaDsp {
+}
+IMG.formulaInl { 
+       vertical-align: middle; 
+}
+SPAN.keyword       { color: #008000 }
+SPAN.keywordtype   { color: #604020 }
+SPAN.keywordflow   { color: #e08000 }
+SPAN.comment       { color: #800000 }
+SPAN.preprocessor  { color: #806020 }
+SPAN.stringliteral { color: #002080 }
+SPAN.charliteral   { color: #008080 }
+SPAN.vhdldigit     { color: #ff00ff }
+SPAN.vhdlchar      { color: #000000 }
+SPAN.vhdlkeyword   { color: #700070 }
+SPAN.vhdllogic     { color: #ff0000 }
+
+.mdescLeft {
+       padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.mdescRight {
+        padding: 0px 8px 4px 8px;
+       font-size: 80%;
+       font-style: italic;
+       background-color: #FAFAFA;
+       border-top: 1px none #E0E0E0;
+       border-right: 1px none #E0E0E0;
+       border-bottom: 1px none #E0E0E0;
+       border-left: 1px none #E0E0E0;
+       margin: 0px;
+}
+.memItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemLeft {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplItemRight {
+       padding: 1px 8px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: none;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.memTemplParams {
+       padding: 1px 0px 0px 8px;
+       margin: 4px;
+       border-top-width: 1px;
+       border-right-width: 1px;
+       border-bottom-width: 1px;
+       border-left-width: 1px;
+       border-top-color: #E0E0E0;
+       border-right-color: #E0E0E0;
+       border-bottom-color: #E0E0E0;
+       border-left-color: #E0E0E0;
+       border-top-style: solid;
+       border-right-style: none;
+       border-bottom-style: none;
+       border-left-style: none;
+       color: #606060;
+       background-color: #FAFAFA;
+       font-size: 80%;
+}
+.search { 
+       color: #003399;
+       font-weight: bold;
+}
+FORM.search {
+       margin-bottom: 0px;
+       margin-top: 0px;
+}
+INPUT.search { 
+       font-size: 75%;
+       color: #000080;
+       font-weight: normal;
+       background-color: #e8eef2;
+}
+TD.tiny { 
+       font-size: 75%;
+}
+a {
+       color: #1A41A8;
+}
+a:visited {
+       color: #2A3798;
+}
+.dirtab { 
+       padding: 4px;
+       border-collapse: collapse;
+       border: 1px solid #84b0c7;
+}
+TH.dirtab { 
+       background: #e8eef2;
+       font-weight: bold;
+}
+HR { 
+       height: 1px;
+       border: none;
+       border-top: 1px solid black;
+}
+
+/* Style for detailed member documentation */
+.memtemplate {
+       font-size: 80%;
+       color: #606060;
+       font-weight: normal;
+       margin-left: 3px;
+} 
+.memnav { 
+       background-color: #e8eef2;
+       border: 1px solid #84b0c7;
+       text-align: center;
+       margin: 2px;
+       margin-right: 15px;
+       padding: 2px;
+}
+.memitem {
+       padding: 4px;
+       background-color: #eef3f5;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #dedeee;
+       -moz-border-radius: 8px 8px 8px 8px;
+}
+.memname {
+       white-space: nowrap;
+       font-weight: bold;
+}
+.memdoc{
+       padding-left: 10px;
+}
+.memproto {
+       background-color: #d5e1e8;
+       width: 100%;
+       border-width: 1px;
+       border-style: solid;
+       border-color: #84b0c7;
+       font-weight: bold;
+       -moz-border-radius: 8px 8px 8px 8px;
+}
+.paramkey {
+       text-align: right;
+}
+.paramtype {
+       white-space: nowrap;
+}
+.paramname {
+       color: #602020;
+       font-style: italic;
+       white-space: nowrap;
+}
+/* End Styling for detailed member documentation */
+
+/* for the tree view */
+.ftvtree {
+       font-family: sans-serif;
+       margin:0.5em;
+}
+/* these are for tree view when used as main index */
+.directory { 
+       font-size: 9pt; 
+       font-weight: bold; 
+}
+.directory h3 { 
+       margin: 0px; 
+       margin-top: 1em; 
+       font-size: 11pt; 
+}
+
+/* The following two styles can be used to replace the root node title */
+/* with an image of your choice.  Simply uncomment the next two styles, */
+/* specify the name of your image and be sure to set 'height' to the */
+/* proper pixel height of your image. */
+
+/* .directory h3.swap { */
+/*     height: 61px; */
+/*     background-repeat: no-repeat; */
+/*     background-image: url("yourimage.gif"); */
+/* } */
+/* .directory h3.swap span { */
+/*     display: none; */
+/* } */
+
+.directory > 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 (file)
index 0000000..b24f3a4
Binary files /dev/null and b/doc/img/foot_bg.png differ
diff --git a/doc/img/head_bg.png b/doc/img/head_bg.png
new file mode 100644 (file)
index 0000000..081dc13
Binary files /dev/null and b/doc/img/head_bg.png differ
diff --git a/doc/img/menu_bg.png b/doc/img/menu_bg.png
new file mode 100644 (file)
index 0000000..e978743
Binary files /dev/null and b/doc/img/menu_bg.png differ
diff --git a/doc/img/menu_bg_current.png b/doc/img/menu_bg_current.png
new file mode 100644 (file)
index 0000000..de97c92
Binary files /dev/null and b/doc/img/menu_bg_current.png differ
diff --git a/doc/img/menu_bg_hover.png b/doc/img/menu_bg_hover.png
new file mode 100644 (file)
index 0000000..3fd851d
Binary files /dev/null and b/doc/img/menu_bg_hover.png differ
diff --git a/doc/img/menu_bg_last.png b/doc/img/menu_bg_last.png
new file mode 100644 (file)
index 0000000..88c116c
Binary files /dev/null and b/doc/img/menu_bg_last.png differ
diff --git a/doc/img/menu_bg_unsel.png b/doc/img/menu_bg_unsel.png
new file mode 100644 (file)
index 0000000..50e5fd8
Binary files /dev/null and b/doc/img/menu_bg_unsel.png differ
diff --git a/eio.manifest b/eio.manifest
new file mode 100644 (file)
index 0000000..97e8c31
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+       <request>
+               <domain name="_"/>
+       </request>
+</manifest>
diff --git a/eio.spec.in b/eio.spec.in
new file mode 100644 (file)
index 0000000..280981e
--- /dev/null
@@ -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 <mej@eterm.org>}
+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 (file)
index 0000000..2a809ad
--- /dev/null
@@ -0,0 +1,63 @@
+dnl Copyright (C) 2008 Vincent Torri <vtorri at univ-evry dot fr>
+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 (file)
index 0000000..33d15a3
--- /dev/null
@@ -0,0 +1,206 @@
+dnl Copyright (C) 2010 Vincent Torri <vtorri at univ-evry dot fr>
+dnl rwlock code added by Mike Blumenkrantz <mike at zentific dot com>
+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.h>
+                       ]],
+                       [[
+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.h>
+                       ]],
+                       [[
+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 (file)
index 0000000..1d5e3f4
--- /dev/null
@@ -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 <asm/unistd.h>
+           #include <linux/inotify.h>
+          ],
+          [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 (file)
index 0000000..8996afd
--- /dev/null
@@ -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
index 2433e6c..34a2f0e 100644 (file)
@@ -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 (file)
index 0000000..73a8df7
--- /dev/null
@@ -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 (file)
index 0000000..7a9e7f5
--- /dev/null
@@ -0,0 +1,74 @@
+/**
+  * Compile with gcc -o eio_file_ls eio_file_ls.c `pkg-config --cflags --libs ecore eio`
+  */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <Eio.h>
+#include <Ecore.h>
+
+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;
+}
index fc2336a..cb791a0 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) 2010 Enlightenment Developers:
  *           Cedric Bail <cedric.bail@free.fr>
  *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *          Stephen "okra" Houston <unixtitan@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #ifndef EIO_H__
 # define EIO_H__
 
-#ifdef _MSC_VER
-# include <Evil.h>
-#endif
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include <Eina.h>
+#include <Eet.h>
 
 #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
 # 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
index d2bdf3b..73d3c23 100644 (file)
@@ -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 (file)
index 0000000..7bed4fb
--- /dev/null
@@ -0,0 +1,1001 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2010 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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(&copy->progress.common.data, handler, info))
+     return EINA_FALSE;
+
+   switch (info->type)
+     {
+      case EINA_FILE_UNKNOWN:
+         eio_file_thread_error(&copy->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, &copy->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, &copy->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, &copy->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, &copy->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(&copy->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, &copy->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(&copy->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(&copy->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 &copy->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 (file)
index 0000000..049c1e3
--- /dev/null
@@ -0,0 +1,640 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2010 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *           Stephen "okra" Houston <UnixTitan@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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;
+}
index bf5c197..31122d0 100644 (file)
@@ -2,6 +2,7 @@
  * Copyright (C) 2010 Enlightenment Developers:
  *           Cedric Bail <cedric.bail@free.fr>
  *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *           Stephen "okra" Houston <UnixTitan@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
  * if not, see <http://www.gnu.org/licenses/>.
  */
 
-#ifdef HAVE_CONFIG_H
-# include "config.h"
+#include "eio_private.h"
+#include "Eio.h"
+
+#ifdef HAVE_XATTR
+# include <sys/xattr.h>
 #endif
 
-#include <Ecore.h>
+/*============================================================================*
+ *                                  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(&copy->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, &copy->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(&copy->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(&copy->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(&copy->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(&copy->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 &copy->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 (file)
index 0000000..af49646
--- /dev/null
@@ -0,0 +1,105 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2010 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *          Stephen "okra" Houston <unixtitan@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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 (file)
index 0000000..e65f75b
--- /dev/null
@@ -0,0 +1,300 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2010 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+#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 (file)
index 0000000..9edc0ad
--- /dev/null
@@ -0,0 +1,316 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2010 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *           Stephen "okra" Houston <UnixTitan@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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 (file)
index 0000000..9f735d6
--- /dev/null
@@ -0,0 +1,351 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2011 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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 (file)
index 0000000..b5ffabd
--- /dev/null
@@ -0,0 +1,273 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2011 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "eio_private.h"
+#include "Eio.h"
+
+#ifdef HAVE_SYS_INOTIFY
+# include <sys/inotify.h>
+#else
+# include <asm/unistd.h>
+# include <linux/inotify.h>
+#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 (file)
index 0000000..1f09a42
--- /dev/null
@@ -0,0 +1,354 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2011 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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 (file)
index 0000000..16dbaa7
--- /dev/null
@@ -0,0 +1,425 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2011 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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 (file)
index 0000000..ef983f9
--- /dev/null
@@ -0,0 +1,512 @@
+#ifndef EIO_PRIVATE_H_
+#define EIO_PRIVATE_H_
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <sys/types.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+# define NAMLEN(dirent) strlen ((dirent)->d_name)
+#else
+# define dirent direct
+# define NAMLEN(dirent) ((dirent)->d_namlen)
+# ifdef HAVE_SYS_NDIR_H
+#  include <sys/ndir.h>
+# endif
+# ifdef HAVE_SYS_DIR_H
+#  include <sys/dir.h>
+# endif
+# ifdef HAVE_NDIR_H
+#  include <ndir.h>
+# endif
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+
+#ifdef HAVE_PWD_H
+# include <pwd.h>
+#endif
+
+#ifdef HAVE_FEATURES_H
+# include <features.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifdef HAVE_LIBGEN_H
+# include <libgen.h>
+#endif
+
+#ifdef HAVE_GRP_H
+# include <grp.h>
+#endif
+
+#ifdef EFL_HAVE_POSIX_THREADS
+# include <pthread.h>
+#endif
+
+#ifdef EFL_HAVE_WIN32_THREADS
+# ifndef WIN32_LEAN_AND_MEAN
+#  define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# undef WIN32_LEAN_AND_MEAN
+#endif
+
+#ifdef HAVE_EVIL
+# include <Evil.h>
+#endif
+
+#include <Ecore.h>
+
+#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 (file)
index 0000000..8bc99fa
--- /dev/null
@@ -0,0 +1,594 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2010 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *           Vincent "caro" Torri  <vtorri at univ-evry dot fr>
+ *           Stephen "okra" Houston <UnixTitan@gmail.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+#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 (file)
index 0000000..cff21b9
--- /dev/null
@@ -0,0 +1,500 @@
+/* EIO - EFL data type library
+ * Copyright (C) 2011 Enlightenment Developers:
+ *           Cedric Bail <cedric.bail@free.fr>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#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);
+}