Patches for aports can be sent to this list

1

[alpine-aports] [PATCH] testing/csync2: upgrade to 2.0

Valery Kartel
Details
Message ID
<1443100651-13963-1-git-send-email-valery.kartel@gmail.com>
Sender timestamp
1443100651
DKIM signature
missing
Download raw message
Patch: +132 -6752
---
 testing/csync2/03-strlcpy_disable.patch         |   21 -
 testing/csync2/APKBUILD                         |   94 +-
 testing/csync2/csync2-1.34-librsync-1.0.0.patch |   35 -
 testing/csync2/csync2.initd                     |   13 +
 testing/csync2/csync2.post-install              |   24 +
 testing/csync2/csync2.post-upgrade              |    6 +
 testing/csync2/git.patch                        | 6640 -----------------------
 testing/csync2/longlong-format.patch            |   31 +
 testing/csync2/rsync-strlcpy-disable.patch      |   20 +
 9 files changed, 132 insertions(+), 6752 deletions(-)
 delete mode 100644 testing/csync2/03-strlcpy_disable.patch
 delete mode 100644 testing/csync2/csync2-1.34-librsync-1.0.0.patch
 create mode 100644 testing/csync2/csync2.initd
 create mode 100644 testing/csync2/csync2.post-install
 create mode 100644 testing/csync2/csync2.post-upgrade
 delete mode 100644 testing/csync2/git.patch
 create mode 100644 testing/csync2/longlong-format.patch
 create mode 100644 testing/csync2/rsync-strlcpy-disable.patch

diff --git a/testing/csync2/03-strlcpy_disable.patch b/testing/csync2/03-strlcpy_disable.patch
deleted file mode 100644
index f0e9d45..0000000
--- a/testing/csync2/03-strlcpy_disable.patch
@@ -1,21 +0,0 @@
---- old/rsync.c
-+++ new/rsync.c
-@@ -49,6 +49,9 @@
-  *
-  * @return index of the terminating byte.
-  **/
-+
-+/* disabled **
-+
- static size_t strlcpy(char *d, const char *s, size_t bufsize)
- {
-         size_t len = strlen(s);
-@@ -61,7 +64,7 @@
-         }
-         return ret;
- }
--
-+*/
- 
- /* This has been taken from rsync sources: receiver.c */
- 
diff --git a/testing/csync2/APKBUILD b/testing/csync2/APKBUILD
index f26da55..5b32bad 100644
--- a/testing/csync2/APKBUILD
+++ b/testing/csync2/APKBUILD
@@ -1,83 +1,65 @@
-# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
 pkgname=csync2
-pkgver=1.34_git20111201
-_ver=${pkgver%_git*}
-pkgrel=2
+pkgver=2.0
+pkgrel=0
 pkgdesc="Cluster synchronization tool"
 url="http://oss.linbit.com/csync2/"
 arch="all"
 license="GPL-2+"
-depends=
-makedepends="librsync-dev gnutls-dev sqlite-dev autoconf automake bison flex"
-install=
-subpackages="$pkgname-doc"
-source="http://oss.linbit.com/csync2/csync2-${_ver}.tar.gz
-	git.patch
-	03-strlcpy_disable.patch
-	csync2-1.34-librsync-1.0.0.patch
-	"
-#	01-csync2-sqlite3.patch
-#	02-csync2-1.34-gnutls_pkgconfig.patch
+makedepends="librsync-dev gnutls-dev sqlite-dev mysql-dev postgresql-dev"
+subpackages="$pkgname-compare $pkgname-doc"
+source="http://oss.linbit.com/$pkgname/$pkgname-$pkgver.tar.gz
+	longlong-format.patch
+	rsync-strlcpy-disable.patch
+	$pkgname.initd"
+install="$pkgname.post-install $pkgname.post-upgrade"
 
-_builddir="$srcdir"/$pkgname-$_ver
-_giturl="http://git.linbit.com/csync2.git"
+_builddir="$srcdir"/$pkgname-$pkgver
 
-
-snapshot() {                                                                
-        local _pkg=$pkgname-$pkgver.tar.gz                                   
-        mkdir -p "$srcdir"                                                  
-        cd "$srcdir"                                                        
-        msg "Creating snapshot: $_pkg"                                      
- 	rm -rf ${_giturl##*/}                                               
-	git clone --bare $_giturl || return 1                     
-        git --git-dir ${_giturl##*/} archive -o $_pkg \
-             --prefix=$pkgname-$pkgver/ HEAD \
-            || return 1                             
-        	
-        msg "New snapshot: $_pkg"
-        if [ -n "$_upload" ]; then                    
-             msg "Uploading to $_upload"           
-             scp $_pkg $_upload || return 1     
-             abump $pkgname-$_tag          
-        fi   
-        #abuild checksum                                
-}
-
-prepare() {                                             
+prepare() {
 	cd "$_builddir"
 	for i in $source; do
 		case $i in
 		*.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;;
 		esac
 	done
-	autoreconf --install --force 
 }
-    
+
 build() {
 	cd "$_builddir"
 	./configure --prefix=/usr \
-		--sysconfdir=/etc \
+		--sysconfdir=/etc/$pkgname \
 		--localstatedir=/var \
+		--docdir=/usr/share/doc/$pkgname \
 		--mandir=/usr/share/man \
-		--infodir=/usr/share/info \
+		--enable-postgres \
+		--enable-mysql \
 		|| return 1
 	make || return 1
 }
 
 package() {
 	cd "$_builddir"
-	make DESTDIR="$pkgdir" install
+	make DESTDIR="$pkgdir" install || return 1
+	install -m755 -D "$srcdir"/$pkgname.initd "$pkgdir"/etc/init.d/$pkgname
+	cp doc/* "$pkgdir"/usr/share/doc/$pkgname/
 }
 
-md5sums="efc8a3548996b79cef2ad76af5e93cd8  csync2-1.34.tar.gz
-bd4957d25e984518d929ae4036bf0ae9  git.patch
-e6d8aaff70cf847b11873cd1cfaaa8f6  03-strlcpy_disable.patch
-943227a4ca4bdd5ec37a315dba1844d3  csync2-1.34-librsync-1.0.0.patch"
-sha256sums="32b250dd4a0353f71015c5c3961174b975dd5e799e4a084e8f6d00792bd8c833  csync2-1.34.tar.gz
-7174ff0cb464b8f74c3816bfe3c5a89e9b876b50dcd6a7440b7488e3561668d7  git.patch
-f4a44ca3f3a33a413a96ce837d5569c3d802bce4a6a960593b014d8dcbfbc136  03-strlcpy_disable.patch
-320ac974d6bbebddea5bc08b92c944189733742e2db8c3580e193ca9a2b934ee  csync2-1.34-librsync-1.0.0.patch"
-sha512sums="a24154446740f3362c10a23d526c29e96292f2ad56a9ed2f11ca0a6d7afed3730d0e96f8ebc2c6cdcc17031aa0e368f6ba93084ad3cf5f4828fbc279e6f004d8  csync2-1.34.tar.gz
-ff47b30e86f6266b4be85a47db52409169597d97e4ec086653af3341978cce5e477054e5746f3824aed1d8c7949e5f8451b2bd675442a9a2c9c5c519918438a9  git.patch
-1b82b25acfb988cd8f92117f6ea4bc22247648448751adc0958dae0ade3c1eb065ad15f7104e4860ea2f08a91a368d68e3959ef5dfa278c254857382ebb64625  03-strlcpy_disable.patch
-f44e1df35aefff2900a5983fd1e368864396757e1fcfd6e3f5d39a55c1bad6e42e8bca5f0e16aa641dff3b62a27d7d5413dc907bcd19b9d4de068fd7be7214b0  csync2-1.34-librsync-1.0.0.patch"
+compare() {
+	subpkgdesc="csync2 compare script"
+	arch="noarch"
+	depents="bash perl-digest-md5"
+	mkdir -p "$subpkgdir"/usr/sbin
+	mv "$pkgdir"/usr/sbin/$pkgname-compare "$subpkgdir"/usr/sbin/
+}
+md5sums="4069fc9e86e8508c392fe2862059eb91  csync2-2.0.tar.gz
+8fc73254db29316f9125761d18f1ed46  longlong-format.patch
+5908c4106d4866ab1c1f88f4c9482c9f  rsync-strlcpy-disable.patch
+05df8f2b877e7d8ca838df9e71bf2c65  csync2.initd"
+sha256sums="11cb37380fb185bce0c22b804fec9b01c385d9d83cc528cfd48d748453834fa2  csync2-2.0.tar.gz
+afb1317987cc4b81908bc437269162c7af23b34e6842306483da5b53efce2db3  longlong-format.patch
+339c7f5d91ff7ed3e63de5a5e39cf17efd7533f9c460eb81db76003acb164017  rsync-strlcpy-disable.patch
+77f6baf688fdb6938846e9f6e0e945d4085d2f0002661ff335e5c8ac39f0069a  csync2.initd"
+sha512sums="f91fd222f67affe9634471d341b43ff67854a6ed25b620301a454e98a79a9fb80b2a66eb8713546758fd08300d52751e5ca7472c696daa20ee11779b87a830f8  csync2-2.0.tar.gz
+38a17cbf23cbccd4996ad1af049851e33179586e619e3f3edbfacbaa36662e44d916839acd59b1cfc67b3af9042c3258068ec9e5b57f7e26c00a41a0e6f0e148  longlong-format.patch
+c44ad7e7fb7093f66fd9582b5309e3929dfdf7b76ef4d234d346fa25158f088b9436db9a1989d036d739570459867210d053af62125facb66e4f5202448c7bea  rsync-strlcpy-disable.patch
+96e5fb1a8865981a014f368b3a644659d048183534a72332718aa815fdf28180e758005e8ae7c438bb8b36134719c2597dd44fc09c85ba13e150f6d396d6b25b  csync2.initd"
diff --git a/testing/csync2/csync2-1.34-librsync-1.0.0.patch b/testing/csync2/csync2-1.34-librsync-1.0.0.patch
deleted file mode 100644
index d46653d..0000000
--- a/testing/csync2/csync2-1.34-librsync-1.0.0.patch
@@ -1,35 +0,0 @@
-Patch by Robert Scheck <robert@fedoraproject.org> for csync2 <= 1.34 based on the
-patch by Roman Tereshonkov and Kari Hautio to avoid a build failure with librsync
->= 1.0.0 (which is a security bugfix release). The discussion and solution finding
-can be found at https://bugs.launchpad.net/duplicity/+bug/1416344 (for duplicity).
-
---- csync2-1.34/rsync.c				2007-07-24 23:04:18.000000000 +0200
-+++ csync2-1.34/rsync.c.librsync-1.0.0		2015-03-02 00:18:43.000000000 +0100
-@@ -134,8 +134,13 @@
- 
- 	if ( isreg ) {
- 		csync_debug(3, "Running rs_sig_file() from librsync....\n");
-+#ifdef RS_DEFAULT_STRONG_LEN
- 		result = rs_sig_file(basis_file, sig_file,
- 				RS_DEFAULT_BLOCK_LEN, RS_DEFAULT_STRONG_LEN, &stats);
-+#else /* librsync >= 1.0.0 */
-+		result = rs_sig_file(basis_file, sig_file,
-+				RS_DEFAULT_BLOCK_LEN, 8, RS_MD4_SIG_MAGIC, &stats);
-+#endif
- 		if (result != RS_DONE) {
- 			csync_debug(0, "Internal error from rsync library!\n");
- 			goto error;
-@@ -216,8 +221,13 @@
- 	if ( !basis_file ) basis_file = fopen("/dev/null", "rb");
- 
- 	csync_debug(3, "Running rs_sig_file() from librsync..\n");
-+#ifdef RS_DEFAULT_STRONG_LEN
- 	result = rs_sig_file(basis_file, sig_file,
- 			RS_DEFAULT_BLOCK_LEN, RS_DEFAULT_STRONG_LEN, &stats);
-+#else /* librsync >= 1.0.0 */
-+	result = rs_sig_file(basis_file, sig_file,
-+			RS_DEFAULT_BLOCK_LEN, 8, RS_MD4_SIG_MAGIC, &stats);
-+#endif
- 	if (result != RS_DONE)
- 		csync_fatal("Got an error from librsync, too bad!\n");
- 
diff --git a/testing/csync2/csync2.initd b/testing/csync2/csync2.initd
new file mode 100644
index 0000000..0caa339
--- /dev/null
+++ b/testing/csync2/csync2.initd
@@ -0,0 +1,13 @@
+#!/sbin/openrc-run
+
+name="$SVCNAME"
+pidfile="/var/run/$SVCNAME.pid"
+command="/usr/sbin/$SVCNAME"
+command_args="-ii"
+command_background="yes"
+required_files="/etc/csync2/csync2.cfg /etc/csync2/csync2_ssl_key.pem /etc/csync2/csync2_ssl_cert.pem"
+
+depend() {
+    need net localmount
+    after firewall
+}
diff --git a/testing/csync2/csync2.post-install b/testing/csync2/csync2.post-install
new file mode 100644
index 0000000..3c2ecc1
--- /dev/null
+++ b/testing/csync2/csync2.post-install
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+SSL="/etc/csync2/csync2_ssl_"
+SERV="/etc/services"
+INETD="/etc/inetd.conf"
+
+if [ ! -f ${SSL}key.pem -o ! -f ${SSL}cert.pem ]; then
+	openssl genrsa -out ${SSL}key.pem 1024 &> /dev/null
+	yes '' | openssl req -new -key ${SSL}key.pem -out ${SSL}cert.csr &> /dev/null
+	openssl x509 -req -days 3600 -in ${SSL}cert.csr -out ${SSL}cert.pem -signkey ${SSL}key.pem &> /dev/null
+	rm ${SSL}cert.csr
+fi
+
+if [ ! -f ${SERV} ]; then
+	touch ${SERV}
+fi
+grep -q csync2 ${SERV} || echo -e "csync2\t\t30865/tcp" >> ${SERV}
+
+if [ ! -f ${INETD} ]; then
+	touch ${INETD}
+fi
+grep -q csync2 ${INETD} || echo "csync2 stream tcp nowait root /usr/sbin/csync2 csync2 -i" >> ${INETD}
+
+exit 0
diff --git a/testing/csync2/csync2.post-upgrade b/testing/csync2/csync2.post-upgrade
new file mode 100644
index 0000000..26f8e45
--- /dev/null
+++ b/testing/csync2/csync2.post-upgrade
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+mv /etc/csync2.cfg /etc/csync2/ &> /dev/null
+mv /etc/csync2_ssl_*.pem /etc/csync2/ &> /dev/null
+
+exit 0
diff --git a/testing/csync2/git.patch b/testing/csync2/git.patch
deleted file mode 100644
index 5d9b709..0000000
--- a/testing/csync2/git.patch
@@ -1,6640 +0,0 @@
-diff --git a/AUTHORS b/AUTHORS
-index 74faa05..45ed0d7 100644
---- a/AUTHORS
-+++ b/AUTHORS
-@@ -1 +1,8 @@
-+LINBIT Information Technologies GmbH <http://www.linbit.com>
- Clifford Wolf <clifford@clifford.at>
-+
-+With contributions from:
-+
-+Lars Ellenberg <lars.ellenberg@linbit.at>
-+Johannes Thoma <johannes.thoma@gmx.at>
-+Dennis Schafroth <dennis@schafroth.dk>
-diff --git a/ChangeLog b/ChangeLog
-index 52fa2a2..9d9f791 100644
---- a/ChangeLog
-+++ b/ChangeLog
-@@ -1,2 +1,2 @@
- Please fetch the ChangeLog directly from the subversion repository:
--svn log -v http://svn.clifford.at/csync2/
-+svn log -v http://svn.linbit.com/csync2/
-diff --git a/Makefile.am b/Makefile.am
-index e3ec933..adbf68d 100644
---- a/Makefile.am
-+++ b/Makefile.am
-@@ -23,16 +23,27 @@ man_MANS = csync2.1
- 
- csync2_SOURCES = action.c cfgfile_parser.y cfgfile_scanner.l check.c	\
-                  checktxt.c csync2.c daemon.c db.c error.c getrealfn.c	\
--                 groups.c rsync.c update.c urlencode.c conn.c prefixsubst.c
-+                 groups.c rsync.c update.c urlencode.c conn.c prefixsubst.c \
-+		 db_api.c db_sqlite.c db_sqlite2.c db_mysql.c db_postgres.c \
-+		 csync2.h db_api.h db_mysql.h db_postgres.h db_sqlite.h db_sqlite2.h dl.h \
-+		 csync2-compare \
-+		 csync2.1
-+
-+EXTRA_DIST = csync2.cfg csync2.xinetd
- 
- AM_YFLAGS = -d
- BUILT_SOURCES = cfgfile_parser.h
-+LIBS += -ldl
- CLEANFILES = cfgfile_parser.c cfgfile_parser.h cfgfile_scanner.c	\
--             private_librsync private_libsqlite config.log		\
--             config.status config.h .deps/*.Po stamp-h1 Makefile
-+             private_librsync private_libsqlite config.log		
-+
-+DISTCLEANFILES = config.status config.h .deps/*.Po stamp-h1 Makefile Makefile.in configure
-+
-+dist-clean-local:
-+	rm -rf autom4te.cache
- 
--AM_CFLAGS=
--AM_LDFLAGS=
-+AM_CFLAGS=$(LIBGNUTLS_CFLAGS)
-+AM_LDFLAGS=$(LIBGNUTLS_LIBS)
- 
- if PRIVATE_LIBRSYNC
-   BUILT_SOURCES += private_librsync
-@@ -41,13 +52,6 @@ if PRIVATE_LIBRSYNC
-   LIBS += -lprivatersync
- endif
- 
--if PRIVATE_LIBSQLITE
--  BUILT_SOURCES += private_libsqlite
--  AM_CFLAGS += -I$(shell test -f libsqlite.dir && cat libsqlite.dir || echo ==libsqlite==)
--  AM_LDFLAGS += -L$(shell test -f libsqlite.dir && cat libsqlite.dir || echo ==libsqlite==)
--  LIBS += -lprivatesqlite
--endif
--
- AM_CPPFLAGS  = -D'DBDIR="$(localstatedir)/lib/csync2"'
- AM_CPPFLAGS += -D'ETCDIR="$(sysconfdir)"'
- 
-diff --git a/README b/README
-index ed6eb6b..7dbbae1 100644
---- a/README
-+++ b/README
-@@ -12,7 +12,7 @@ better have a look at Unison (http://www.cis.upenn.edu/~bcpierce/unison/)
- too.
- 
- See http://oss.linbit.com/ for more information on csync2. The csync2
--subversion tree can be found at http://svn.clifford.at/csync2/.
-+subversion tree can be found at http://svn.linbit.com/csync2/.
- 
- 
- Copyright
-@@ -76,3 +76,25 @@ There is a csync2 mailing list:
- It is recommended to subscribe to this list if you are using csync2 in
- production environments.
- 
-+Building csync2
-+===============
-+
-+You'll need the GNU autotools and a compiler toolchain (gcc) for 
-+building csync2.
-+
-+First, run the autogen.sh script:
-+
-+karin$ ./autogen.sh
-+
-+Then run configure, use ./configure --help for more options:
-+
-+karin$ ./configure
-+
-+Then run make:
-+
-+karin$ make
-+
-+csync2 should be built now. Direct any questions to the csync2 mailing list
-+(see above).
-+
-+- Johannes
-diff --git a/TODO b/TODO
-index 6c02fc3..0ee83ff 100644
---- a/TODO
-+++ b/TODO
-@@ -1 +1,74 @@
- Universal peace and a good attitude for everyone.
-+
-+Check for mysql/mysql.h to exist in configure.
-+	Done
-+
-+DB abstraction: check for installed databases on configure
-+	and enable/disable them for compilation.
-+
-+Create MySQL database if it doesn't exist.
-+
-+Implement table creation with schema support.
-+	We don't have a schema table yet, add it when it is needed.
-+
-+Have check return value for asprintf () .. have a macro that does a csync_fatal 
-+	if there is no memory.
-+
-+Make database configurable.
-+
-+From Dennis:
-+Filename column is too short, but this is due to the fact that mysql 5 only 
-+supports keys length of max 1000 bytes.
-+So the filename+peername must be below 333 UTF characters (since mysql looks at 
-+worst-case when generating the tables). 
-+	Sort of fixed. Fields are 4096 bytes now (highest MAXPATHLEN of all
-+	supported platforms) but only the first 1000 chars are unique.
-+
-+sqlite3:// url not working
-+	It works but it needs an extra slash like in sqlite3:///var/lib/... 
-+	Now have a howto if slash is missing and database file is not found.
-+
-+-a should be stronger than configured database in /etc/csync2.cfg
-+	Works now.
-+
-+test long filenames with mysql
-+	Work now
-+
-+From Dennis:
-+Weird characters in filename cuts off the filename at the character. I have a 
-+danish letter (å encoded in iso-8859-1: \370) still present in my 
-+now UTF-8 filesystem names. 
-+	Couldn't reproduce tried with German umlauts.
-+
-+---------------------------------------------------------------------------
-+
-+Test schema support for SQLite 2.
-+
-+Have command to pipe connection through (for SSH support for example)
-+
-+From Gerhard Rieger:
-+If there are more than one node to sync with print nodes that are not reachable.
-+	Done, test it
-+
-+	Segfault when syncing a file where one side is a directory and the other one
-+		is a link.
-+
-+postgres support
-+
-+dl_open for all sql related calls
-+	we don't want to depend on libmysql/libsqlite/whatever on install.
-+	TODO: how to express that we need at least one sql client library in Debian/RPM
-+
-+Performance tests: when does it make sense to use mysql instead of sqlite?
-+
-+Have schema version table.
-+
-+Compile even when there is no libsqlite (mysql support only)
-+
-+From Martin: Provide up-to-date packages.
-+	Resuse build.sh script from drbd-proxy.
-+
-+Build packages for all supported distros.
-+
-+If include <dir> is missing error message is Permission denied, which is 
-+    irritating.
-diff --git a/action.c b/action.c
-index 438db5c..9ac8126 100644
---- a/action.c
-+++ b/action.c
-@@ -38,14 +38,18 @@ void csync_schedule_commands(const char *filename, int islocal)
- 
- 	while ( (g=csync_find_next(g, filename)) ) {
- 		for (a=g->action; a; a=a->next) {
-+			if ( !islocal && a->do_local_only )
-+				continue;
- 			if ( islocal && !a->do_local )
- 				continue;
- 			if (!a->pattern)
- 				goto found_matching_pattern;
--			for (p=a->pattern; p; p=p->next)
-+			for (p=a->pattern; p; p=p->next) {
-+				int fnm_pathname = p->star_matches_slashes ? 0 : FNM_PATHNAME;
- 				if ( !fnmatch(p->pattern, filename,
--						FNM_LEADING_DIR|FNM_PATHNAME) )
-+						FNM_LEADING_DIR|fnm_pathname) )
- 					goto found_matching_pattern;
-+			}
- 			continue;
- found_matching_pattern:
- 			for (c=a->command; c; c=c->next)
-@@ -69,7 +73,7 @@ void csync_run_single_command(const char *command, const char *logfile)
- 			"SELECT filename from action WHERE command = '%s' "
- 			"and logfile = '%s'", command, logfile)
- 	{
--		textlist_add(&tl, SQL_V[0], 0);
-+		textlist_add(&tl, SQL_V(0), 0);
- 	} SQL_END;
- 
- 	mark = strstr(command_clr, "%%");
-@@ -107,7 +111,7 @@ void csync_run_single_command(const char *command, const char *logfile)
- 		/* 1 */ open(logfile_clr, O_WRONLY|O_CREAT|O_APPEND, 0666);
- 		/* 2 */ open(logfile_clr, O_WRONLY|O_CREAT|O_APPEND, 0666);
- 
--		execl("/bin/sh", "sh", "-c", real_command, 0);
-+		execl("/bin/sh", "sh", "-c", real_command, NULL);
- 		_exit(127);
- 	}
- 
-@@ -130,7 +134,7 @@ void csync_run_commands()
- 	SQL_BEGIN("Checking for sceduled commands",
- 			"SELECT command, logfile FROM action GROUP BY command, logfile")
- 	{
--		textlist_add2(&tl, SQL_V[0], SQL_V[1], 0);
-+		textlist_add2(&tl, SQL_V(0), SQL_V(1), 0);
- 	} SQL_END;
- 
- 	for (t = tl; t != 0; t = t->next)
-diff --git a/autogen.sh b/autogen.sh
-index df9e797..85663ac 100755
---- a/autogen.sh
-+++ b/autogen.sh
-@@ -18,9 +18,9 @@
- # along with this program; if not, write to the Free Software
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- 
--aclocal-1.7
-+aclocal
- autoheader
--automake-1.7 --add-missing --copy
-+automake --add-missing --copy
- autoconf
- 
- if [ "$1" = clean ]; then
-@@ -32,5 +32,13 @@ if [ "$1" = clean ]; then
- 	rm -rf config.guess config.sub
- 	rm -rf cygwin/librsync-0.9.7.tar.gz
- 	rm -rf cygwin/sqlite-2.8.16.tar.gz
-+else
-+	./configure  --prefix=/usr --localstatedir=/var --sysconfdir=/etc
-+
-+	echo ""
-+	echo "Configured as"
-+	echo "./configure  --prefix=/usr --localstatedir=/var --sysconfdir=/etc"
-+	echo ""
-+	echo "reconfigure, if you want it different"
- fi
- 
-diff --git a/cfgfile_parser.y b/cfgfile_parser.y
-index 776bbcf..7f493ab 100644
---- a/cfgfile_parser.y
-+++ b/cfgfile_parser.y
-@@ -33,6 +33,8 @@ struct csync_nossl  *csync_nossl  = 0;
- int csync_ignore_uid = 0;
- int csync_ignore_gid = 0;
- int csync_ignore_mod = 0;
-+unsigned csync_lock_timeout = 12;
-+char *csync_tempdir = NULL;
- 
- #ifdef __CYGWIN__
- int csync_lowercyg_disable = 0;
-@@ -51,11 +53,12 @@ void yyerror(char *text)
- static void new_group(char *name)
- {
- 	int static autonum = 1;
-+	int rc; 
- 	struct csync_group *t =
- 		calloc(sizeof(struct csync_group), 1);
- 
- 	if (name == 0)
--		asprintf(&name, "group_%d", autonum++);
-+		rc = asprintf(&name, "group_%d", autonum++);
- 
- 	t->next = csync_group;
- 	t->auto_method = -1;
-@@ -106,12 +109,17 @@ static void add_patt(int patterntype, char *pattern)
- 	}
- #endif
- 
-+	/* strip trailing slashes from pattern */
- 	for (i=strlen(pattern)-1; i>0; i--)
- 		if (pattern[i] == '/')
- 			pattern[i] = 0;
- 		else
- 			break;
- 
-+	/* if you use ** at least once anywhere in the pattern,
-+	 * _all_ stars in the pattern, even single ones,
-+	 * will match slashes. */
-+	t->star_matches_slashes = !!strstr(pattern, "**");
- 	t->isinclude = patterntype >= 1;
- 	t->iscompare = patterntype >= 2;
- 	t->pattern = pattern;
-@@ -280,6 +288,7 @@ static void add_action_pattern(const char *pattern)
- {
- 	struct csync_group_action_pattern *t =
- 		calloc(sizeof(struct csync_group_action_pattern), 1);
-+	t->star_matches_slashes = !!strstr(pattern, "**");
- 	t->pattern = pattern;
- 	t->next = csync_group->action->pattern;
- 	csync_group->action->pattern = t;
-@@ -304,6 +313,28 @@ static void set_action_dolocal()
- 	csync_group->action->do_local = 1;
- }
- 
-+static void set_action_dolocal_only()
-+{
-+	csync_group->action->do_local = 1;
-+	csync_group->action->do_local_only = 1;
-+}
-+
-+static void set_lock_timeout(const char *timeout)
-+{
-+	csync_lock_timeout = atoi(timeout);
-+}
-+
-+static void set_tempdir(const char *tempdir)
-+{
-+	csync_tempdir = strdup(tempdir);
-+}
-+
-+static void set_database(const char *filename)
-+{
-+	if (!csync_database)
-+		csync_database = strdup(filename);
-+}
-+
- static void new_prefix(const char *pname)
- {
- 	struct csync_prefix *p =
-@@ -392,10 +423,12 @@ static void disable_cygwin_lowercase_hack()
- }
- 
- %token TK_BLOCK_BEGIN TK_BLOCK_END TK_STEND TK_AT TK_AUTO
--%token TK_NOSSL TK_IGNORE TK_GROUP TK_HOST TK_EXCL TK_INCL TK_COMP TK_KEY
-+%token TK_NOSSL TK_IGNORE TK_GROUP TK_HOST TK_EXCL TK_INCL TK_COMP TK_KEY TK_DATABASE
- %token TK_ACTION TK_PATTERN TK_EXEC TK_DOLOCAL TK_LOGFILE TK_NOCYGLOWER
- %token TK_PREFIX TK_ON TK_COLON TK_POPEN TK_PCLOSE
--%token TK_BAK_DIR TK_BAK_GEN
-+%token TK_BAK_DIR TK_BAK_GEN TK_DOLOCALONLY
-+%token TK_TEMPDIR
-+%token TK_LOCK_TIMEOUT
- %token <txt> TK_STRING
- 
- %%
-@@ -413,9 +446,15 @@ block:
- 		{ }
- |	TK_NOSSL TK_STRING TK_STRING TK_STEND
- 		{ new_nossl($2, $3); }
-+|	TK_DATABASE TK_STRING TK_STEND
-+		{ set_database($2); }
-+|	TK_TEMPDIR TK_STRING TK_STEND
-+		{ set_tempdir($2); }
- |	TK_IGNORE ignore_list TK_STEND
- |	TK_NOCYGLOWER TK_STEND
- 		{ disable_cygwin_lowercase_hack(); }
-+|	TK_LOCK_TIMEOUT TK_STRING TK_STEND
-+		{ set_lock_timeout($2); }
- ;
- 
- ignore_list:
-@@ -517,6 +556,8 @@ action_stmt:
- 		{ set_action_logfile($2); }
- |	TK_DOLOCAL
- 		{ set_action_dolocal(); }
-+|	TK_DOLOCALONLY
-+		{ set_action_dolocal_only(); }
- ;
- 
- action_pattern_list:
-diff --git a/cfgfile_scanner.l b/cfgfile_scanner.l
-index 77daf5f..5e93f7c 100644
---- a/cfgfile_scanner.l
-+++ b/cfgfile_scanner.l
-@@ -25,9 +25,13 @@
- #define MAX_INCLUDE_DEPTH 10
- YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
- int include_stack_ptr = 0;
-+
-+#define YY_NO_INPUT 1
-+#define YY_NO_UNPUT 1
- %}
- 
- %option noyywrap yylineno
-+%option nounput
- %x STRING INCL
- 
- %%
-@@ -42,6 +46,7 @@ int include_stack_ptr = 0;
- 
- "nossl"		{ return TK_NOSSL; }
- "ignore"	{ return TK_IGNORE; }
-+"database"	{ return TK_DATABASE; }
- 
- "group"		{ return TK_GROUP; }
- "host"		{ return TK_HOST; }
-@@ -56,10 +61,13 @@ int include_stack_ptr = 0;
- "exec"		{ return TK_EXEC; }
- "logfile"	{ return TK_LOGFILE; }
- "do-local"	{ return TK_DOLOCAL; }
-+"do-local-only"	{ return TK_DOLOCALONLY; }
- 
- "prefix"	{ return TK_PREFIX; }
- "on"		{ return TK_ON; }
- 
-+"lock-timeout"		{ return TK_LOCK_TIMEOUT; }
-+"tempdir"		{ return TK_TEMPDIR; }
- "backup-directory"	{ return TK_BAK_DIR; }
- "backup-generations"	{ return TK_BAK_GEN; }
- 
-diff --git a/check.c b/check.c
-index 360abd3..c5b9f32 100644
---- a/check.c
-+++ b/check.c
-@@ -99,15 +99,20 @@ void csync_mark(const char *file, const char *thispeer, const char *peerfilter)
- 
- 	csync_debug(1, "Marking file as dirty: %s\n", file);
- 	for (pl_idx=0; pl[pl_idx].peername; pl_idx++)
--		if (!peerfilter || !strcmp(peerfilter, pl[pl_idx].peername))
-+		if (!peerfilter || !strcmp(peerfilter, pl[pl_idx].peername)) {
-+			SQL("Deleting old dirty file entries",
-+				"DELETE FROM dirty WHERE filename = '%s' AND peername = '%s'",
-+				url_encode(file),
-+				url_encode(pl[pl_idx].peername));
-+
- 			SQL("Marking File Dirty",
--				"%s INTO dirty (filename, force, myname, peername) "
-+				"INSERT INTO dirty (filename, forced, myname, peername) "
- 				"VALUES ('%s', %s, '%s', '%s')",
--				csync_new_force ? "REPLACE" : "INSERT",
- 				url_encode(file),
- 				csync_new_force ? "1" : "0",
- 				url_encode(pl[pl_idx].myname),
- 				url_encode(pl[pl_idx].peername));
-+		}
- 
- 	free(pl);
- }
-@@ -122,21 +127,83 @@ int csync_check_pure(const char *filename)
- 	if (!csync_lowercyg_disable)
- 		return 0;
- #endif
--
- 	struct stat sbuf;
--	int i=0;
-+	int dir_len = 0;
-+	int i;
-+	int same_len;
-+
-+	/* single entry last query cache
-+	 * to speed up checks from deep subdirs */
-+	static struct {
-+		/* store inclusive trailing slash for prefix match */
-+		char *path;
-+		/* strlen(path) */
-+		int len;
-+		/* cached return value */
-+		int has_symlink;
-+	} cached;
-+
-+	for (i = 0; filename[i]; i++)
-+		if (filename[i] == '/')
-+			dir_len = i+1;
-+
-+	if (dir_len <= 1) /* '/' a symlink? hardly. */
-+		return 0;
-+
-+	/* identical prefix part */
-+	for (i = 0; i < dir_len && i < cached.len; i++)
-+		if (filename[i] != cached.path[i])
-+			break;
-+
-+	/* backtrack to slash */
-+	for (--i; i >= 0 && cached.path[i] != '/'; --i);
-+		;
- 
--	while (filename[i]) i++;
-+	same_len = i+1;
-+
-+	csync_debug(3, " check: %s %u, %s %u, %u.\n", filename, dir_len, cached.path, cached.len, same_len);
-+	/* exact match? */
-+	if (dir_len == same_len && same_len == cached.len)
-+		return cached.has_symlink;
- 
- 	{ /* new block for myfilename[] */
--		char myfilename[i+1];
--		memcpy(myfilename, filename, i+1);
--		while (1) {
--			while (myfilename[i] != '/')
--				if (--i <= 0) return 0;
-+		char myfilename[dir_len+1];
-+		char *to_be_cached;
-+		int has_symlink = 0;
-+		memcpy(myfilename, filename, dir_len);
-+		myfilename[dir_len] = '\0';
-+		to_be_cached = strdup(myfilename);
-+		i = dir_len-1;
-+		while (i) {
-+			for (; i && myfilename[i] != '/'; --i)
-+				;
-+
-+			if (i <= 1)
-+				break;
-+
-+			if (i+1 == same_len) {
-+				if (same_len == cached.len) {
-+					/* exact match */
-+					has_symlink = cached.has_symlink;
-+					break;
-+				} else if (!cached.has_symlink)
-+					/* prefix of something 'pure' */
-+					break;
-+			}
-+
- 			myfilename[i]=0;
--			if ( lstat_strict(prefixsubst(myfilename), &sbuf) || S_ISLNK(sbuf.st_mode) ) return 1;
-+			if (lstat_strict(prefixsubst(myfilename), &sbuf) || S_ISLNK(sbuf.st_mode)) {
-+				has_symlink = 1;
-+				break;
-+			}
- 		}
-+		if (to_be_cached) { /* strdup can fail. So what. */
-+			free(cached.path);
-+			cached.path = to_be_cached;
-+			cached.len = dir_len;
-+			cached.has_symlink = has_symlink;
-+		}
-+		return has_symlink;
- 	}
- }
- 
-@@ -148,18 +215,22 @@ void csync_check_del(const char *file, int recursive, int init_run)
- 
- 	if ( recursive ) {
- 		if ( !strcmp(file, "/") )
--			asprintf(&where_rec, "or 1");
-+		  ASPRINTF(&where_rec, "OR 1=1");
- 		else
--			asprintf(&where_rec, "or (filename > '%s/' "
--					"and filename < '%s0')",
--					url_encode(file), url_encode(file));
-+		  ASPRINTF(&where_rec, "UNION ALL SELECT filename from file where filename > '%s/' "
-+				"and filename < '%s0'",
-+				url_encode(file), url_encode(file));
- 	}
- 
- 	SQL_BEGIN("Checking for removed files",
- 			"SELECT filename from file where "
- 			"filename = '%s' %s ORDER BY filename", url_encode(file), where_rec)
- 	{
--		const char *filename = url_decode(SQL_V[0]);
-+		const char *filename = url_decode(SQL_V(0));
-+
-+		if (!csync_match_file(filename))
-+			continue;
-+
- 		if ( lstat_strict(prefixsubst(filename), &st) != 0 || csync_check_pure(filename) )
- 			textlist_add(&tl, filename, 0);
- 	} SQL_END;
-@@ -231,7 +302,7 @@ int csync_check_mod(const char *file, int recursive, int ignnoent, int init_run)
- 			"filename = '%s'", url_encode(file))
- 		{
- 			if ( !csync_cmpchecktxt(checktxt,
--						url_decode(SQL_V[0])) ) {
-+						url_decode(SQL_V(0))) ) {
- 				csync_debug(2, "File has changed: %s\n", file);
- 				this_is_dirty = 1;
- 			}
-@@ -243,6 +314,10 @@ int csync_check_mod(const char *file, int recursive, int ignnoent, int init_run)
- 		} SQL_END;
- 
- 		if ( this_is_dirty && !csync_compare_mode ) {
-+			SQL("Deleting old file entry",
-+			    "DELETE FROM file WHERE filename = '%s'",
-+			    url_encode(file));
-+
- 			SQL("Adding or updating file entry",
- 			    "INSERT INTO file (filename, checktxt) "
- 			    "VALUES ('%s', '%s')",
-diff --git a/configure.ac b/configure.ac
-index 6ec6136..8989a33 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -17,15 +17,15 @@
- # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
- 
- # Process this file with autoconf to produce a configure script.
--AC_INIT(csync2, 1.34, clifford@clifford.at)
-+AC_INIT(csync2, 2.0rc1, csync2@lists.linbit.com)
- AM_INIT_AUTOMAKE
- 
- AC_CONFIG_SRCDIR(csync2.c)
- AM_CONFIG_HEADER(config.h)
- 
- # Use /etc and /var instead of $prefix/...
--test "$localstatedir" = '${prefix}/var' && localstatedir=/var
--test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
-+# test "$localstatedir" = '${prefix}/var' && localstatedir=/var
-+# test "$sysconfdir" = '${prefix}/etc' && sysconfdir=/etc
- 
- # Checks for programs.
- AC_PROG_CC
-@@ -33,6 +33,9 @@ AC_PROG_INSTALL
- AC_PROG_YACC
- AM_PROG_LEX
- 
-+# check for large file support
-+AC_SYS_LARGEFILE
-+
- # Check for librsync.
- AC_ARG_WITH([librsync-source],
- 	AS_HELP_STRING([--with-librsync-source=source-tar-file],
-@@ -42,35 +45,78 @@ AC_ARG_WITH([librsync-source],
- )
- AM_CONDITIONAL([PRIVATE_LIBRSYNC], [test -n "$librsync_source_file"])
- 
--# Check for libsqlite.
--AC_ARG_WITH([libsqlite-source],
--	AS_HELP_STRING([--with-libsqlite-source=source-tar-file],
--		[build this libsqlite and link statically against it (hack! hack!)]),
--	AC_SUBST([libsqlite_source_file], $withval),
--	AC_CHECK_LIB([sqlite], [sqlite_exec], , [AC_MSG_ERROR(libsqlite is required)])
--)
--AM_CONDITIONAL([PRIVATE_LIBSQLITE], [test -n "$libsqlite_source_file"])
-+AC_ARG_ENABLE([sqlite],
-+	[AC_HELP_STRING([--enable-sqlite],
-+		[enable/disable sqlite 2 support (default is disabled)])],
-+	[], [ enable_sqlite=no ])
-+
-+if test "$enable_sqlite" == yes
-+then
-+        AC_CHECK_HEADERS([sqlite.h], , [AC_MSG_ERROR([[SQLite header not found; install libsqlite-dev and dependencies for SQLite 2 support]])])
-+
-+	AC_DEFINE([HAVE_SQLITE], 1, [Define if sqlite 2 support is wanted])
-+fi
-+
-+AC_ARG_ENABLE([sqlite3],
-+	[AC_HELP_STRING([--disable-sqlite3],
-+		[enable/disable sqlite3 support (default is enabled)])],
-+	[], [ enable_sqlite3=yes ])
-+
-+if test "$enable_sqlite3" == yes
-+then
-+        AC_CHECK_HEADERS([sqlite3.h], , [AC_MSG_ERROR([[SQLite header not found; install libsqlite3-dev and dependencies for SQLite 3 support]])])
-+
-+	AC_DEFINE([HAVE_SQLITE3], 1, [Define if sqlite3 support is wanted])
-+fi
- 
- AC_ARG_ENABLE([gnutls],
--	[AC_HELP_STRING([--disable-gnutls],
--		[enable/disable GNU TLS support (default is enabled)])],
-+	[AS_HELP_STRING([--disable-gnutls],[enable/disable GNU TLS support (default is enabled)])],
- 	[], [ enable_gnutls=yes ])
- 
- if test "$enable_gnutls" != no
- then
-+   PKG_PROG_PKG_CONFIG
-+   PKG_CHECK_MODULES([LIBGNUTLS], [gnutls >= 2.6.0], [
-+      AC_DEFINE([HAVE_LIBGNUTLS], 1, [Define to 1 when using GNU TLS library])
-+   ])
-+fi
- 
--	# Check for gnuTLS.
--	AM_PATH_LIBGNUTLS(1.0.0, , [ AC_MSG_ERROR([[gnutls not found; install gnutls, gnutls-openssl and libtasn1 packages for your system or run configure with --disable-gnutls]]) ])
-+AC_ARG_ENABLE([mysql],
-+	[AC_HELP_STRING([--enable-mysql],
-+		[enable/disable MySQL support (default is disabled)])],
-+	[], [ enable_mysql=no ])
- 
-+AC_ARG_ENABLE([postgres],
-+	[AC_HELP_STRING([--enable-postgres],
-+		[enable/disable Postgres support (default is disabled)])],
-+	[], [ enable_postgres=no ])
-+
-+if test "$enable_mysql" == yes
-+then
-+	# Check for mysql.
- 	# This is a bloody hack for fedora core
--	CFLAGS="$CFLAGS $LIBGNUTLS_CFLAGS"
--	LIBS="$LIBS $LIBGNUTLS_LIBS -ltasn1"
-+	CFLAGS="$CFLAGS `mysql_config --cflags`"	
-+
-+	# Check MySQL development header
-+	AC_CHECK_HEADERS([mysql/mysql.h], , [AC_MSG_ERROR([[mysql header not found; install mysql-devel and dependencies for MySQL Support]])])
- 
--	# Check gnuTLS SSL compatibility lib.
--	AC_CHECK_LIB([gnutls-openssl], [SSL_new], , [AC_MSG_ERROR([[gnutls-openssl not found; install gnutls, gnutls-openssl and libtasn1 packages for your system or run configure with --disable-gnutls]])])
-+	AC_DEFINE([HAVE_MYSQL], 1, [Define if mysql support is wanted])
-+fi
-+
-+if test "$enable_postgres" == yes
-+then
-+        AC_CHECK_HEADERS([postgresql/libpq-fe.h], , [AC_MSG_ERROR([[postgres header not found; install libpq-dev and dependencies for Postgres support]])])
- 
-+	AC_DEFINE([HAVE_POSTGRES], 1, [Define if postgres support is wanted])
-+fi
-+
-+# at least one db backend must be configured.
-+
-+if test "$enable_postgres" != yes && test "$enable_mysql" != yes &&
-+   test "$enable_sqlite3" != yes && test "$enable_sqlite" != yes
-+then
-+	AC_MSG_ERROR([No database backend configured. Please enable either sqlite, sqlite3, mysql or postgres.])
- fi
- 
- AC_CONFIG_FILES([Makefile])
- AC_OUTPUT
--
-diff --git a/conn.c b/conn.c
-index 6f8dfdc..8dda10d 100644
---- a/conn.c
-+++ b/conn.c
-@@ -30,52 +30,77 @@
- #include <netdb.h>
- #include <errno.h>
- 
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- #  include <gnutls/gnutls.h>
--#  include <gnutls/openssl.h>
-+#  include <gnutls/x509.h>
- #endif
- 
- int conn_fd_in  = -1;
- int conn_fd_out = -1;
- int conn_clisok = 0;
- 
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- int csync_conn_usessl = 0;
- 
--SSL_METHOD *conn_ssl_meth;
--SSL_CTX *conn_ssl_ctx;
--SSL *conn_ssl;
-+static gnutls_session_t conn_tls_session;
-+static gnutls_certificate_credentials_t conn_x509_cred;
- #endif
- 
-+
-+/* getaddrinfo stuff mostly copied from its manpage */
-+int conn_connect(const char *peername)
-+{
-+	struct addrinfo hints;
-+	struct addrinfo *result, *rp;
-+	int sfd, s;
-+
-+	/* Obtain address(es) matching host/port */
-+	memset(&hints, 0, sizeof(struct addrinfo));
-+	hints.ai_family = AF_UNSPEC;	/* Allow IPv4 or IPv6 */
-+	hints.ai_socktype = SOCK_STREAM;
-+	hints.ai_flags = 0;
-+	hints.ai_protocol = 0;	/* Any protocol */
-+
-+	s = getaddrinfo(peername, csync_port, &hints, &result);
-+	if (s != 0) {
-+		csync_debug(1, "Cannot resolve peername, getaddrinfo: %s\n", gai_strerror(s));
-+		return -1;
-+	}
-+
-+	/* getaddrinfo() returns a list of address structures.
-+	   Try each address until we successfully connect(2).
-+	   If socket(2) (or connect(2)) fails, we (close the socket
-+	   and) try the next address. */
-+
-+	for (rp = result; rp != NULL; rp = rp->ai_next) {
-+		sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-+		if (sfd == -1)
-+			continue;
-+
-+		if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
-+			break;	/* Success */
-+
-+		close(sfd);
-+	}
-+	freeaddrinfo(result);	/* No longer needed */
-+
-+	if (rp == NULL)	/* No address succeeded */
-+		return -1;
-+
-+	return sfd;
-+}
-+
- int conn_open(const char *peername)
- {
--        struct sockaddr_in sin;
--        struct hostent *hp;
- 	int on = 1;
- 
--        hp = gethostbyname(peername);
--        if ( ! hp ) {
--                csync_debug(1, "Can't resolve peername.\n");
--                return -1;
--        }
--
--        conn_fd_in = socket(hp->h_addrtype, SOCK_STREAM, 0);
-+        conn_fd_in = conn_connect(peername);
-         if (conn_fd_in < 0) {
-                 csync_debug(1, "Can't create socket.\n");
-                 return -1;
-         }
- 
--        sin.sin_family = hp->h_addrtype;
--        bcopy(hp->h_addr, &sin.sin_addr, hp->h_length);
--        sin.sin_port = htons(csync_port);
--
--        if (connect(conn_fd_in, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
--                csync_debug(1, "Can't connect to remote host.\n");
--		close(conn_fd_in); conn_fd_in = -1;
--                return -1;
--        }
--
--	if (setsockopt(conn_fd_in, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on) ) < 0 ) {
-+	if (setsockopt(conn_fd_in, IPPROTO_TCP, TCP_NODELAY, &on, sizeof(on) ) < 0) {
-                 csync_debug(1, "Can't set TCP_NODELAY option on TCP socket.\n");
- 		close(conn_fd_in); conn_fd_in = -1;
-                 return -1;
-@@ -83,10 +108,9 @@ int conn_open(const char *peername)
- 
- 	conn_fd_out = conn_fd_in;
- 	conn_clisok = 1;
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- 	csync_conn_usessl = 0;
- #endif
--
- 	return 0;
- }
- 
-@@ -97,12 +121,13 @@ int conn_set(int infd, int outfd)
- 	conn_fd_in  = infd;
- 	conn_fd_out = outfd;
- 	conn_clisok = 1;
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- 	csync_conn_usessl = 0;
- #endif
- 
- 	// when running in server mode, this has been done already
- 	// in csync2.c with more restrictive error handling..
-+	// FIXME don't even try in "ssh" mode
- 	if ( setsockopt(conn_fd_out, IPPROTO_TCP, TCP_NODELAY, &on, (socklen_t) sizeof(on)) < 0 )
-                 csync_debug(1, "Can't set TCP_NODELAY option on TCP socket.\n");
- 
-@@ -110,43 +135,106 @@ int conn_set(int infd, int outfd)
- }
- 
- 
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
-+
-+static void ssl_log(int level, const char* msg)
-+{ csync_debug(level, "%s", msg); }
- 
--char *ssl_keyfile = ETCDIR "/csync2_ssl_key.pem";
--char *ssl_certfile = ETCDIR "/csync2_ssl_cert.pem";
-+static const char *ssl_keyfile = ETCDIR "/csync2_ssl_key.pem";
-+static const char *ssl_certfile = ETCDIR "/csync2_ssl_cert.pem";
- 
- int conn_activate_ssl(int server_role)
- {
--	static int sslinit = 0;
-+	gnutls_alert_description_t alrt;
-+	int err;
- 
- 	if (csync_conn_usessl)
- 		return 0;
- 
--	if (!sslinit) {
--		SSL_load_error_strings();
--		SSL_library_init();
--		sslinit=1;
--	}
-+	gnutls_global_init();
-+	gnutls_global_set_log_function(ssl_log);
-+	gnutls_global_set_log_level(10);
- 
--	conn_ssl_meth = (server_role ? SSLv23_server_method : SSLv23_client_method)();
--	conn_ssl_ctx = SSL_CTX_new(conn_ssl_meth);
-+	gnutls_certificate_allocate_credentials(&conn_x509_cred);
- 
--	if (SSL_CTX_use_PrivateKey_file(conn_ssl_ctx, ssl_keyfile, SSL_FILETYPE_PEM) <= 0)
--		csync_fatal("SSL: failed to use key file %s.\n", ssl_keyfile);
-+	err = gnutls_certificate_set_x509_key_file(conn_x509_cred, ssl_certfile, ssl_keyfile, GNUTLS_X509_FMT_PEM);
-+	if(err != GNUTLS_E_SUCCESS) {
-+		gnutls_certificate_free_credentials(conn_x509_cred);
-+		gnutls_global_deinit();
- 
--	if (SSL_CTX_use_certificate_file(conn_ssl_ctx, ssl_certfile, SSL_FILETYPE_PEM) <= 0)
--		csync_fatal("SSL: failed to use certificate file %s.\n", ssl_certfile);
-+		csync_fatal(
-+			"SSL: failed to use key file %s and/or certificate file %s: %s (%s)\n",
-+			ssl_keyfile,
-+			ssl_certfile,
-+			gnutls_strerror(err),
-+			gnutls_strerror_name(err)
-+		);
-+	}
- 
--	if (! (conn_ssl = SSL_new(conn_ssl_ctx)) )
--		csync_fatal("Creating a new SSL handle failed.\n");
-+	if(server_role) {
-+		gnutls_certificate_free_cas(conn_x509_cred);
- 
--	gnutls_certificate_server_set_request(conn_ssl->gnutls_state, GNUTLS_CERT_REQUIRE);
-+		if(gnutls_certificate_set_x509_trust_file(conn_x509_cred, ssl_certfile, GNUTLS_X509_FMT_PEM) < 1) {
-+			gnutls_certificate_free_credentials(conn_x509_cred);
-+			gnutls_global_deinit();
- 
--	SSL_set_rfd(conn_ssl, conn_fd_in);
--	SSL_set_wfd(conn_ssl, conn_fd_out);
-+			csync_fatal(
-+				"SSL: failed to use certificate file %s as CA.\n",
-+				ssl_certfile
-+			);
-+		}
-+	} else
-+		gnutls_certificate_free_ca_names(conn_x509_cred);
-+
-+	gnutls_init(&conn_tls_session, (server_role ? GNUTLS_SERVER : GNUTLS_CLIENT));
-+	gnutls_priority_set_direct(conn_tls_session, "PERFORMANCE", NULL);
-+	gnutls_credentials_set(conn_tls_session, GNUTLS_CRD_CERTIFICATE, conn_x509_cred);
- 
--	if ( (server_role ? SSL_accept : SSL_connect)(conn_ssl) < 1 )
--		csync_fatal("Establishing SSL connection failed.\n");
-+	if(server_role) {
-+		gnutls_certificate_send_x509_rdn_sequence(conn_tls_session, 0);
-+		gnutls_certificate_server_set_request(conn_tls_session, GNUTLS_CERT_REQUIRE);
-+	}
-+
-+	gnutls_transport_set_ptr2(
-+		conn_tls_session,
-+		(gnutls_transport_ptr_t)conn_fd_in,
-+		(gnutls_transport_ptr_t)conn_fd_out
-+	);
-+
-+	err = gnutls_handshake(conn_tls_session);
-+	switch(err) {
-+	case GNUTLS_E_SUCCESS:
-+		break;
-+
-+	case GNUTLS_E_WARNING_ALERT_RECEIVED:
-+		alrt = gnutls_alert_get(conn_tls_session);
-+		fprintf(
-+			csync_debug_out,
-+			"SSL: warning alert received from peer: %d (%s).\n",
-+			alrt, gnutls_alert_get_name(alrt)
-+		);
-+		break;
-+
-+	case GNUTLS_E_FATAL_ALERT_RECEIVED:
-+		alrt = gnutls_alert_get(conn_tls_session);
-+		fprintf(
-+			csync_debug_out,
-+			"SSL: fatal alert received from peer: %d (%s).\n",
-+			alrt, gnutls_alert_get_name(alrt)
-+		);
-+
-+	default:
-+		gnutls_bye(conn_tls_session, GNUTLS_SHUT_RDWR);
-+		gnutls_deinit(conn_tls_session);
-+		gnutls_certificate_free_credentials(conn_x509_cred);
-+		gnutls_global_deinit();
-+
-+		csync_fatal(
-+			"SSL: handshake failed: %s (%s)\n",
-+			gnutls_strerror(err),
-+			gnutls_strerror_name(err)
-+		);
-+	}
- 
- 	csync_conn_usessl = 1;
- 
-@@ -155,15 +243,15 @@ int conn_activate_ssl(int server_role)
- 
- int conn_check_peer_cert(const char *peername, int callfatal)
- {
--	const X509 *peercert;
-+	const gnutls_datum_t *peercerts;
-+	unsigned npeercerts;
- 	int i, cert_is_ok = -1;
- 
- 	if (!csync_conn_usessl)
- 		return 1;
- 
--	peercert = SSL_get_peer_certificate(conn_ssl);
--
--	if (!peercert || peercert->size <= 0) {
-+	peercerts = gnutls_certificate_get_peers(conn_tls_session, &npeercerts);
-+	if(peercerts == NULL || npeercerts == 0) {
- 		if (callfatal)
- 			csync_fatal("Peer did not provide an SSL X509 cetrificate.\n");
- 		csync_debug(1, "Peer did not provide an SSL X509 cetrificate.\n");
-@@ -171,17 +259,17 @@ int conn_check_peer_cert(const char *peername, int callfatal)
- 	}
- 
- 	{
--		char certdata[peercert->size*2 + 1];
-+		char certdata[2*peercerts[0].size + 1];
- 
--		for (i=0; i<peercert->size; i++)
--			sprintf(certdata+i*2, "%02X", peercert->data[i]);
--		certdata[peercert->size*2] = 0;
-+		for (i=0; i<peercerts[0].size; i++)
-+			sprintf(&certdata[2*i], "%02X", peercerts[0].data[i]);
-+		certdata[2*i] = 0;
- 
- 		SQL_BEGIN("Checking peer x509 certificate.",
- 			"SELECT certdata FROM x509_cert WHERE peername = '%s'",
- 			url_encode(peername))
- 		{
--			if (!strcmp(SQL_V[0], certdata))
-+			if (!strcmp(SQL_V(0), certdata))
- 				cert_is_ok = 1;
- 			else
- 				cert_is_ok = 0;
-@@ -215,14 +303,19 @@ int conn_check_peer_cert(const char *peername, int callfatal)
- 	return 1;
- }
- 
--#endif /* HAVE_LIBGNUTLS_OPENSSL */
-+#endif /* HAVE_LIBGNUTLS */
- 
- int conn_close()
- {
- 	if ( !conn_clisok ) return -1;
- 
--#ifdef HAVE_LIBGNUTLS_OPENSSL
--	if ( csync_conn_usessl ) SSL_free(conn_ssl);
-+#ifdef HAVE_LIBGNUTLS
-+	if ( csync_conn_usessl ) {
-+		gnutls_bye(conn_tls_session, GNUTLS_SHUT_RDWR);
-+		gnutls_deinit(conn_tls_session);
-+		gnutls_certificate_free_credentials(conn_x509_cred);
-+		gnutls_global_deinit();
-+	}
- #endif
- 
- 	if ( conn_fd_in != conn_fd_out) close(conn_fd_in);
-@@ -237,9 +330,9 @@ int conn_close()
- 
- static inline int READ(void *buf, size_t count)
- {
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- 	if (csync_conn_usessl)
--		return SSL_read(conn_ssl, buf, count);
-+		return gnutls_record_recv(conn_tls_session, buf, count);
- 	else
- #endif
- 		return read(conn_fd_in, buf, count);
-@@ -249,9 +342,9 @@ static inline int WRITE(const void *buf, size_t count)
- {
- 	static int n, total;
- 
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- 	if (csync_conn_usessl)
--		return SSL_write(conn_ssl, buf, count);
-+		return gnutls_record_send(conn_tls_session, buf, count);
- 	else
- #endif
- 	{
-@@ -302,7 +395,7 @@ int conn_raw_read(void *buf, size_t count)
- 	return 0;
- }
- 
--void conn_debug(const char *name, const unsigned char*buf, size_t count)
-+void conn_debug(const char *name, const char*buf, size_t count)
- {
- 	int i;
- 
-@@ -365,9 +458,9 @@ void conn_printf(const char *fmt, ...)
- 	conn_write(buffer, size);
- }
- 
--int conn_gets(char *s, int size)
-+size_t conn_gets(char *s, size_t size)
- {
--	int i=0;
-+	size_t i=0;
- 
- 	while (i<size-1) {
- 		int rc = conn_raw_read(s+i, 1);
-diff --git a/contrib/csync2id.pl b/contrib/csync2id.pl
-new file mode 100644
-index 0000000..1b3a5fa
---- /dev/null
-+++ b/contrib/csync2id.pl
-@@ -0,0 +1,359 @@
-+#!/usr/bin/perl -w
-+# Copyright: telegraaf (NL)
-+# Author: ard@telegraafnet.nl
-+# License: GPL v2 or higher
-+use strict;
-+use Linux::Inotify2;
-+use Data::Dumper;
-+use File::Find;
-+use POSIX qw(uname :sys_wait_h);
-+use Sys::Syslog;
-+use Net::Server::Daemonize qw(daemonize);
-+use IO::Select;
-+use Fcntl;
-+
-+
-+my $program="csync2id";
-+my $daemonize=1;
-+my $usesyslog=1;
-+my $pidfile='/var/run/csync2id.pid';
-+my $pidfileboot='/var/run/csync2id.boot.pid';
-+
-+################################################################################
-+# Config items
-+# Overridden by /etc/csync2id.cfg
-+# Normal config in /etc/csync2id.cfg:
-+#
-+# @::dirs=qw( /data1 /data2 );
-+# 1;
-+#
-+# csyncdirhint:  preferred hint command for directories (a single directory name
-+#                will be added)
-+# csyncfilehint: preferred hint command for files (at most $x filenames will be appended)
-+# csynccheck: preferred command scheduled right after the hint, or after a timeout
-+# csyncupdate: preferred command scheduled right after the check
-+# debug: log debug lines
-+# statsdir: file to log the number of watched directories
-+# statchanges: file to log the number of file change events
-+# statsretry: file to log the number of retries needed so far for the hint
-+# dirs: an array of directories which need to be watched recursively
-+################################################################################
-+
-+$::csynchintmaxargs=20;
-+@::csyncdirhint=("/usr/sbin/csync2", "-B","-A","-rh");
-+@::csyncfilehint=("/usr/sbin/csync2", "-B","-A","-h");
-+@::csynccheck=("/usr/sbin/csync2", "-B","-A","-c");
-+@::csyncupdate=("/usr/sbin/csync2", "-B","-A","-u");
-+$::debug=3;
-+$::statsdir="/dev/shm/csyncstats/dirs";
-+$::statschanges="/dev/shm/csyncstats/changes";
-+$::statsretry="/dev/shm/csyncstats/retry";
-+@::dirs=();
-+require "/etc/csync2id.cfg";
-+
-+$daemonize && daemonize(0,0,$pidfileboot);
-+$usesyslog && openlog("$program",'pid','daemon');
-+
-+use constant { LOGERR => 0, LOGWARN => 1, LOGINFO =>2, LOGDEBUG=>3,LOGSLOTS=>256 };
-+my %prios=( 0 => 'err', 1 => 'warning', 2 => 'info', default => 'debug' );
-+sub logger {
-+	my($level,@args)=@_;
-+	my ($prio)=$prios{$level}||$prios{'default'}; # :$prios{'default'};
-+	if($usesyslog) {
-+		syslog($prio,@args) if (($level<= LOGDEBUG && $level<=$::debug)||($::debug>=LOGDEBUG && $level&$::debug)) 
-+	} else {
-+		print "LOG: $prio ";
-+		print(@args);
-+		print "\n";
-+	}
-+}
-+
-+logger(LOGDEBUG,Dumper(\@::dirs));
-+
-+
-+my $inotify = new Linux::Inotify2 or ( logger(LOGERR, "Unable to create new inotify object: $!") && die("inotify") );
-+
-+# For stats
-+my $globaldirs=0;
-+my $globalevents=0;
-+my $globalhintretry=0;
-+
-+sub logstatsline {
-+	my ($file,$line)=@_;
-+#	open STATS,"> $file";
-+#	print STATS $line;
-+#	close STATS;
-+}
-+
-+
-+#package Runner;
-+################################################################################
-+# Process runner
-+# Runs processes and keep status
-+# API:
-+# runstatus: current status of a runslot (running/idle)
-+# exitstatus: last status of an exec
-+# slotrun: forkexec a new command with a callback when it's finished for a specific slot
-+# Helpers:
-+# reaper is the SIGCHLD handler
-+# checkchildren should be called after syscalls which exited with E_INTR, and
-+# calls the specific callbacks.
-+################################################################################
-+use constant { RUN_IDLE => 0, RUN_RUNNING => 1, RUN_REAPED =>2 };
-+my %slotstatus;
-+my %slotexitstatus;
-+my %slotcommandline;
-+my %slotcallback;
-+my %slotpid2slot;
-+my %slotstarttime;
-+
-+# pid queue for reaper
-+# Every pid (key)  contains a waitforpid exit status as value.
-+my %slotpidreaped;
-+
-+sub runstatus {
-+	my ($slot)=@_;
-+	return($slotstatus{$slot}) if exists($slotstatus{$slot});
-+	return RUN_IDLE;
-+}
-+sub slotrun {
-+	my ($slot,$callback,$commandline)=(@_);
-+	$SIG{CHLD} = \&reaper;
-+	if(runstatus($slot)!=RUN_IDLE) {
-+		logger(LOGDEBUG,"SlotRun: Asked to run for $slot, but $slot != RUN_IDLE");
-+		return -1;
-+	}
-+	$slotcommandline{$slot}=$commandline;
-+	$slotcallback{$slot}=$callback;
-+	$slotstatus{$slot}=RUN_RUNNING;
-+	$slotstarttime{$slot}=time();
-+	my $pid=fork();
-+	if(!$pid) {
-+		# We know that exec should not return. Now tell the perl interpreter that we know.
-+		{
-+			exec(@$commandline);
-+		}
-+		logger(LOGWARN,"SlotRun: $slot Exec failed: ".join(' ','>', @$commandline,'<'));
-+		# If we can't exec, we don't really know why, and we don't want to go busy fork execing
-+		# Give a fork exec grace by waiting
-+		sleep 1;
-+		exit 1;
-+	}
-+	logger(LOGDEBUG,"SlotRun: $slot # ".$pid.": run".join(' ','>', @$commandline,'<'));
-+	$slotpid2slot{$pid}=$slot;
-+}
-+sub exitstatus {
-+	my ($slot)=@_;
-+	return($slotexitstatus{$slot}) if exists($slotexitstatus{$slot});
-+	return -1;
-+}
-+sub reaper {
-+}
-+
-+sub checkchildren {
-+	if($::debug==LOGSLOTS) {
-+		while(my ($slot,$status) = each %slotstatus) {
-+			logger(LOGDEBUG,"SlotRun: $slot status $status time: ".($status?(time()-$slotstarttime{$slot}):'x'));
-+		};
-+	}
-+	while() {
-+		my ($pid)=waitpid(-1,&WNOHANG);
-+		if($pid<=0) {
-+			last;
-+		}
-+		my $status=$?;
-+		if (WIFEXITED($status)||WIFSIGNALED($status) && exists($slotpid2slot{$pid})) {
-+			my $slot=$slotpid2slot{$pid};
-+			delete($slotpid2slot{$pid});
-+			$slotstatus{$slot}=RUN_IDLE;
-+			$slotexitstatus{$slot}=$status;
-+			logger(LOGDEBUG, "SlotRun: $slot $pid exited with $status == ".WEXITSTATUS($status).".\n");
-+			# Callback determines if we run again or not.
-+			$slotcallback{$slot}->($slot,$slotexitstatus{$slot},$slotcommandline{$slot});
-+		} else {
-+			logger(LOGDEBUG, "SlotRun: Unknown process $pid change state.\n");
-+		}
-+	}
-+}
-+
-+
-+
-+
-+
-+
-+################################################################################
-+# CSYNC RUNNERS
-+# groups queued hints into single csync commands
-+# run csync update and check commands 
-+################################################################################
-+
-+# use constant { CSYNCHINT => 0 , CSYNCCHECK=>1 , CSYNCUPDATE=>2 };
-+my @hintfifo;
-+
-+sub updateCallback {
-+	my ($slot,$exitstatus,$command)=@_;
-+	if($exitstatus) {
-+		logger(LOGWARN,"Updater got ".$exitstatus.", NOT retrying run:".join(' ','>',@$command,'<'));
-+	}
-+}
-+sub runupdater {
-+	if(runstatus('csupdate') == RUN_IDLE) {
-+		slotrun('csupdate',\&updateCallback,\@::csyncupdate);
-+	}
-+}
-+
-+sub checkerCallback {
-+	my ($slot,$exitstatus,$command)=@_;
-+	if($exitstatus) {
-+		logger(LOGWARN,"Checker got ".$exitstatus.", NOT retrying run:".join(' ','>',@$command,'<'));
-+	}
-+	runupdater();
-+}
-+sub runchecker {
-+	if(runstatus('cscheck') == RUN_IDLE) {
-+		slotrun('cscheck',\&checkerCallback,\@::csynccheck);
-+	}
-+}
-+sub hinterCallback {
-+	my ($slot,$exitstatus,$command)=@_;
-+	if($exitstatus) {
-+		logger(LOGWARN,"Hinter got ".$exitstatus.", retrying run:".join(' ','>',@$command,'<'));
-+		$globalhintretry++;
-+		logstatsline($::statsretry,$globalhintretry);
-+		slotrun($slot,\&hinterCallback,$command);
-+	} else {
-+		runchecker();
-+	}
-+}
-+sub givehints {
-+	if(runstatus('cshint') == RUN_IDLE && @hintfifo) {
-+		# PREPARE JOB
-+		# Directories should be treated with care, one at a time.
-+		my @hintcommand;
-+		if($hintfifo[0]->{'recurse'}) {
-+			my $filename=$hintfifo[0]->{'filename'};
-+			@hintcommand=(@::csyncdirhint,$filename);
-+			shift(@hintfifo) while (@hintfifo && $filename eq $hintfifo[0]->{'filename'} );
-+		} else {
-+			# Files can be bulked, until the next directory
-+			my $nrargs=0;
-+			@hintcommand=(@::csyncfilehint);
-+			while($nrargs < $::csynchintmaxargs && @hintfifo && !$hintfifo[0]->{'recurse'}) {
-+				my $filename=$hintfifo[0]->{'filename'};
-+				push(@hintcommand,$filename);
-+				shift(@hintfifo) while (@hintfifo && $filename eq $hintfifo[0]->{'filename'} );
-+				$nrargs++;
-+			}
-+		}
-+		slotrun('cshint',\&hinterCallback,\@hintcommand);
-+	}
-+}
-+
-+################################################################################
-+# Subtree parser
-+# Adds subtrees to an existing watch
-+# globals: $globaldirs for stats.
-+# Logs to logger
-+################################################################################
-+sub watchtree {
-+	my ($inotifier,$tree,$inotifyflags) = @_;
-+	$inotifier->watch ($tree, $inotifyflags);
-+	$globaldirs++;
-+	find(
-+		sub {
-+			if(! m/^\.\.?$/) {
-+				my ($dev, $ino, $mode, $nlink, $uid, $gid) = lstat($_) ;
-+				if(-d _ ) {
-+					if ($nlink==2) {
-+						$File::Find::prune = 1;
-+					}
-+					$inotifier->watch ($File::Find::dir.'/'.$_, $inotifyflags) or die("WatchTree: watch creation failed (maybe increase the number of watches?)");
-+					$globaldirs++;
-+					logger(LOGDEBUG,"WatchTree: directory ". $globaldirs." ".$File::Find::dir.'/'.$_);
-+				}
-+			}
-+		},
-+		$tree
-+	);
-+	logstatsline($::statsdir,$globaldirs);
-+}
-+
-+
-+################################################################################
-+# Main
-+#
-+logger(LOGINFO, 'Main: Starting $Id: csync2id.pl,v 1.18 2008/12/24 15:34:19 ard Exp $');
-+# Start watching the directories
-+logger(LOGINFO, "Main: traversing directories");
-+eval {
-+	watchtree($inotify,$_,IN_MOVE|IN_DELETE|IN_CLOSE_WRITE|IN_ATTRIB|IN_CREATE) foreach(@::dirs)
-+};
-+if($@) {
-+	logger(LOGERR,"Main: $@");
-+	exit(2);
-+}
-+logger(LOGINFO,"Main: ready for events");
-+
-+# Kill other daemon because we are ready
-+if($daemonize) {
-+	if ( -e $pidfile ) {
-+		my $thepid;
-+		@ARGV=($pidfile);
-+		$thepid=<>;
-+		logger(LOGINFO, "Main: about to kill previous incarnation $thepid");
-+		kill(15,$thepid);
-+		sleep 0.5;
-+	}
-+	rename($pidfileboot,$pidfile);
-+}
-+
-+# Main loop
-+$inotify->blocking(O_NONBLOCK);
-+my $timeout=20;
-+while () {
-+	#my ($rhset,$dummy,$dummy,$timeleft)=IO::Select->select($selectset, undef, undef, 60);
-+	my $nfound;
-+	my $rin='';
-+	vec($rin,$inotify->fileno,1)=1;
-+	($nfound,$timeout)=select($rin, undef, undef, $timeout);
-+	logger(LOGDEBUG,"Main: nrfds: $nfound timeleft: $timeout\n");
-+	if(!$timeout) {
-+		$timeout=20;
-+		logger(LOGDEBUG, "Main: timeout->check and update");
-+		runchecker();
-+		runupdater();
-+		# 
-+	}
-+	if($nfound>0) {
-+		my @events = $inotify->read;
-+		unless (@events > 0) {
-+			logger(LOGWARN,"Main: Zero events, must be a something weird");
-+		}
-+		foreach(@events) {
-+			if($_->IN_Q_OVERFLOW) {
-+				logger(LOGERR,"Main: FATAL:inotify queue overflow: csync2id was to slow to handle events");
-+			}
-+			if( $_->IN_ISDIR) {
-+				my $recurse=0;
-+				# We want to recurse only for new, renamed or deleted directories
-+				$recurse=$_->IN_DELETE||$_->IN_CREATE||$_->IN_MOVED_TO||$_->IN_MOVED_FROM;
-+				eval watchtree($inotify,$_->fullname,IN_MOVE|IN_DELETE|IN_CLOSE_WRITE|IN_ATTRIB|IN_CREATE) if $_->IN_CREATE||$_->IN_MOVED_TO;
-+				if($@) {
-+					logger(LOGINFO,"$@");
-+					exit(3);
-+				}
-+				push(@hintfifo,{ "filename" => $_->fullname , "recurse" => $recurse });
-+				logger(LOGDEBUG,"Main: dir: ".$_->mask." ".$recurse." ".$_->fullname);
-+			} else {
-+				# Accumulate single file events:
-+				next if(@hintfifo && $hintfifo[-1]->{"filename"} eq $_->fullname);
-+				push(@hintfifo,{ "filename" => $_->fullname , "recurse" => 0 });
-+				logger(LOGDEBUG,"Main: file: ".$_->mask," ".$_->fullname);
-+			}
-+			$globalevents++;
-+		}
-+	}
-+	checkchildren();
-+	givehints();
-+	logstatsline($::statschanges,$globalevents);
-+}
-diff --git a/copycheck.sh b/copycheck.sh
-new file mode 100755
-index 0000000..d4fe7d5
---- /dev/null
-+++ b/copycheck.sh
-@@ -0,0 +1,37 @@
-+#!/bin/bash
-+
-+errors=0
-+ignrev="r364"
-+
-+check() {
-+	if ! svn st $1 | grep -q '^?'; then
-+		years="2003 2004 2005 2006 2007 2008"
-+		for y in `svn log $1 | grep '^r[0-9]' | egrep -v "^($ignrev)" | sed 's,.* \(200.\)-.*,\1,' | sort -u`
-+		do
-+			years=`echo $years | sed "s,$y,,"`
-+			if ! grep -q "\*.*Copyright.*$y" $1; then
-+				echo "Missing $y in $1."
-+				(( errors++ ))
-+			fi
-+		done
-+		for y in $years
-+		do
-+			if grep -q "\*.*Copyright.*$y" $1; then
-+				echo "Bogus $y in $1."
-+				(( errors++ ))
-+			fi
-+		done
-+	fi
-+}
-+
-+for f in `grep -rl '\*.*Copyright' . | grep -v '/\.svn/'` ; do
-+	check $f
-+done
-+
-+if [ $errors -ne 0 ]; then
-+	echo "Found $errors errors."
-+	exit 1
-+fi
-+
-+exit 0
-+
-diff --git a/csync2-postgres.sql b/csync2-postgres.sql
-new file mode 100644
-index 0000000..c8975c1
---- /dev/null
-+++ b/csync2-postgres.sql
-@@ -0,0 +1,56 @@
-+--
-+-- Table structure for table action
-+--
-+
-+DROP TABLE IF EXISTS action;
-+CREATE TABLE action (
-+  filename varchar(255) DEFAULT NULL,
-+  command text,
-+  logfile text,
-+  UNIQUE (filename,command)
-+);
-+
-+--
-+-- Table structure for table dirty
-+--
-+
-+DROP TABLE IF EXISTS dirty;
-+CREATE TABLE dirty (
-+  filename varchar(200) DEFAULT NULL,
-+  forced int DEFAULT NULL,
-+  myname varchar(100) DEFAULT NULL,
-+  peername varchar(100) DEFAULT NULL,
-+  UNIQUE (filename,peername)
-+);
-+
-+--
-+-- Table structure for table file
-+--
-+
-+DROP TABLE IF EXISTS file;
-+CREATE TABLE file (
-+  filename varchar(200) DEFAULT NULL,
-+  checktxt varchar(200) DEFAULT NULL,
-+  UNIQUE (filename)
-+);
-+
-+--
-+-- Table structure for table hint
-+--
-+
-+DROP TABLE IF EXISTS hint;
-+CREATE TABLE hint (
-+  filename varchar(255) DEFAULT NULL,
-+  recursive int DEFAULT NULL
-+);
-+
-+--
-+-- Table structure for table x509_cert
-+--
-+
-+DROP TABLE IF EXISTS x509_cert;
-+CREATE TABLE x509_cert (
-+  peername varchar(255) DEFAULT NULL,
-+  certdata varchar(255) DEFAULT NULL,
-+  UNIQUE (peername)
-+);
-diff --git a/csync2.c b/csync2.c
-index 88fefa2..889be05 100644
---- a/csync2.c
-+++ b/csync2.c
-@@ -36,18 +36,25 @@
- #include <errno.h>
- #include <signal.h>
- #include <ctype.h>
-+#include <syslog.h>
-+#include "db_api.h"
-+#include <netdb.h>
- 
- #ifdef REAL_DBDIR
- #  undef DBDIR
- #  define DBDIR REAL_DBDIR
- #endif
- 
--static char *file_database = 0;
-+char *csync_database = 0;
-+
-+int db_type = DB_SQLITE3;
-+
- static char *file_config = 0;
- static char *dbdir = DBDIR;
- char *cfgname = "";
- 
- char myhostname[256] = "";
-+char *csync_port = "30865";
- char *active_grouplist = 0;
- char *active_peerlist = 0;
- 
-@@ -57,11 +64,11 @@ extern FILE *yyin;
- int csync_error_count = 0;
- int csync_debug_level = 0;
- FILE *csync_debug_out = 0;
-+int csync_syslog = 0;
- 
- int csync_server_child_pid = 0;
- int csync_timestamps = 0;
- int csync_new_force = 0;
--int csync_port = 30865;
- 
- int csync_dump_dir_fd = -1;
- 
-@@ -93,6 +100,11 @@ void help(char *cmd)
- PACKAGE_STRING " - cluster synchronization tool, 2nd generation\n"
- "LINBIT Information Technologies GmbH <http://www.linbit.com>\n"
- "Copyright (C) 2004, 2005  Clifford Wolf <clifford@clifford.at>\n"
-+"Copyright (C) 2010  Dennis Schafroth <dennis@schafroth.com>\n"
-+"Copyright (C) 2010  Johannes Thoma <johannes.thoma@gmx.at>\n"
-+"\n"
-+"Version: " CSYNC2_VERSION "\n"
-+"\n"
- "This program is free software under the terms of the GNU GPL.\n"
- "\n"
- "Usage: %s [-v..] [-C config-name] \\\n"
-@@ -103,7 +115,7 @@ PACKAGE_STRING " - cluster synchronization tool, 2nd generation\n"
- "	-c [-r] file..		Check files and maybe add to dirty db\n"
- "	-u [-d] [-r] file..	Updates files if listed in dirty db\n"
- "	-o [-r] file..		Create list of files in compare-mode\n"
--"	-f [-r] file..		Force this file in sync (resolve conflict)\n"
-+"	-f [-r] file..		Force files to win next conflict resolution\n"
- "	-m file..		Mark files in database as dirty\n"
- "\n"
- "Simple mode:\n"
-@@ -161,11 +173,11 @@ PACKAGE_STRING " - cluster synchronization tool, 2nd generation\n"
- "	-U	Don't mark all other peers as dirty when doing a -TI run.\n"
- "\n"
- "	-G Group1,Group2,Group3,...\n"
--"		Only use this groups from config-file.\n"
-+"		Only use these groups from config-file.\n"
- "\n"
- "	-P peer1,peer1,...\n"
--"		Only update this peers (still mark all as dirty).\n"
--"		Only show files for this peers in -o (compare) mode.\n"
-+"		Only update these peers (still mark all as dirty).\n"
-+"		Only show files for these peers in -o (compare) mode.\n"
- "\n"
- "	-F	Add new entries to dirty database with force flag set.\n"
- "\n"
-@@ -178,6 +190,15 @@ PACKAGE_STRING " - cluster synchronization tool, 2nd generation\n"
- "		found to the specified file descriptor (when doing a -c run).\n"
- "		The directory names in this output are zero-terminated.\n"
- "\n"
-+"Database switches:\n"
-+"\n"
-+"	-D database-dir\n"
-+"		Use sqlite database in database dir (default: /var/lib/csync2)\n"
-+"\n"
-+"	-a mysql-url\n"
-+"		Use mysql database in URL:\n"
-+"		mysql://[<user>:<password>@]<hostname>/<database>\n"
-+"\n"
- "Creating key file:\n"
- "	%s -k filename\n"
- "\n"
-@@ -190,69 +211,124 @@ PACKAGE_STRING " - cluster synchronization tool, 2nd generation\n"
- int create_keyfile(const char *filename)
- {
- 	int fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, 0600);
--	int rand = open("/dev/random", O_RDONLY);
-+	int rand = open("/dev/urandom", O_RDONLY);
- 	char matrix[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._";
- 	unsigned char n;
- 	int i;
--
-+	int rc;
- 	assert(sizeof(matrix) == 65);
- 	if ( fd == -1 ) {
- 		fprintf(stderr, "Can't create key file: %s\n", strerror(errno));
- 		return 1;
- 	}
- 	if ( rand == -1 ) {
--		fprintf(stderr, "Can't open /dev/random: %s\n", strerror(errno));
-+		fprintf(stderr, "Can't open /dev/urandom: %s\n", strerror(errno));
- 		return 1;
- 	}
- 	for (i=0; i<64; i++) {
--		read(rand, &n, 1);
--		write(fd, matrix+(n&63), 1);
-+		rc = read(rand, &n, 1);
-+		rc = write(fd, matrix+(n&63), 1);
- 	}
--	write(fd, "\n", 1);
-+	rc = write(fd, "\n", 1);
- 	close(rand);
- 	close(fd);
- 	return 0;
- }
- 
--static int csync_server_loop(int single_connect)
-+static int csync_server_bind(void)
- {
- 	struct linger sl = { 1, 5 };
--	struct sockaddr_in addr;
--	int on = 1;
-+	struct addrinfo hints;
-+	struct addrinfo *result, *rp;
-+	int save_errno;
-+	int sfd, s, on = 1;
-+	memset(&hints, 0, sizeof(struct addrinfo));
-+	hints.ai_family = AF_UNSPEC;	/* Allow IPv4 or IPv6 */
-+	hints.ai_socktype = SOCK_STREAM;
-+	hints.ai_flags = AI_PASSIVE;
-+
-+	s = getaddrinfo(NULL, csync_port, &hints, &result);
-+	if (s != 0) {
-+		csync_debug(1, "Cannot prepare local socket, getaddrinfo: %s\n", gai_strerror(s));
-+		return -1;
-+	}
- 
--	int listenfd = socket(AF_INET, SOCK_STREAM, 0);
--	if (listenfd < 0) goto error;
-+	/* getaddrinfo() returns a list of address structures.
-+	   Try each address until we successfully bind(2).
-+	   If socket(2) (or bind(2)) fails, we (close the socket
-+	   and) try the next address. */
-+
-+	for (rp = result; rp != NULL; rp = rp->ai_next) {
-+		sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
-+		if (sfd == -1)
-+			continue;
-+
-+		if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t) sizeof(on)) < 0)
-+			goto error;
-+		if (setsockopt(sfd, SOL_SOCKET, SO_LINGER, &sl, (socklen_t) sizeof(sl)) < 0)
-+			goto error;
-+		if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &on, (socklen_t) sizeof(on)) < 0)
-+			goto error;
- 
--	bzero(&addr, sizeof(addr));
--	addr.sin_family = AF_INET;
--	addr.sin_addr.s_addr = htonl(INADDR_ANY);
--	addr.sin_port = htons(csync_port);
-+		if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0)
-+			break;	/* Success */
-+
-+		close(sfd);
-+	}
- 
--	if ( setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, (socklen_t) sizeof(on)) < 0 ) goto error;
--	if ( setsockopt(listenfd, SOL_SOCKET, SO_LINGER, &sl, (socklen_t) sizeof(sl)) < 0 ) goto error;
--	if ( setsockopt(listenfd, IPPROTO_TCP, TCP_NODELAY, &on, (socklen_t) sizeof(on)) < 0 ) goto error;
-+	freeaddrinfo(result);	/* No longer needed */
- 
--	if ( bind(listenfd, (struct sockaddr *) &addr, sizeof(addr)) < 0 ) goto error;
--	if ( listen(listenfd, 5) < 0 ) goto error;
-+	if (rp == NULL)	/* No address succeeded */
-+		return -1;
-+
-+	return sfd;
-+
-+error:
-+	save_errno = errno;
-+	close(sfd);
-+	errno = save_errno;
-+	return -1;
-+}
- 
-+static int csync_server_loop(int single_connect)
-+{
-+	union {
-+		struct sockaddr sa;
-+		struct sockaddr_in sa_in;
-+		struct sockaddr_in6 sa_in6;
-+		struct sockaddr_storage ss;
-+	} addr;
-+	int listenfd = csync_server_bind();
-+	if (listenfd < 0) goto error;
-+
-+	if (listen(listenfd, 5) < 0) goto error;
-+
-+	/* we want to "cleanly" shutdown if the connection is lost unexpectedly */
- 	signal(SIGPIPE, SIG_IGN);
-+	/* server is not interested in its childs, prevent zombies */
- 	signal(SIGCHLD, SIG_IGN);
- 
- 	printf("Csync2 daemon running. Waiting for connections.\n");
- 
- 	while (1) {
--		int addrlen = sizeof(addr);
--		int conn = accept(listenfd, (struct sockaddr *) &addr, &addrlen);
-+		unsigned addrlen = sizeof(addr);
-+		int conn = accept(listenfd, &addr.sa, &addrlen);
- 		if (conn < 0) goto error;
- 
- 		fflush(stdout); fflush(stderr);
- 
- 		if (single_connect || !fork()) {
-+			char hbuf[NI_MAXHOST], sbuf[NI_MAXSERV];
-+			/* need to restore default SIGCHLD handler in the session,
-+			 * as we may need to wait on them in action.c */
-+			signal(SIGCHLD, SIG_DFL);
- 			csync_server_child_pid = getpid();
--			fprintf(stderr, "<%d> New connection from %s:%u.\n",
--				csync_server_child_pid,
--				inet_ntoa(addr.sin_addr),
--				ntohs(addr.sin_port));
-+			if (getnameinfo(&addr.sa, addrlen,
-+					hbuf, sizeof(hbuf), sbuf, sizeof(sbuf),
-+					NI_NUMERICHOST | NI_NUMERICSERV) != 0)
-+				goto error;
-+			fprintf(stderr, "<%d> New connection from %s:%s.\n",
-+				csync_server_child_pid, hbuf, sbuf);
- 			fflush(stderr);
- 
- 			dup2(conn, 0);
-@@ -293,8 +369,13 @@ int main(int argc, char ** argv)
- 		return 1;
- 	}
- 
--	while ( (opt = getopt(argc, argv, "W:s:Ftp:G:P:C:D:N:HBAIXULSTMRvhcuoimfxrd")) != -1 ) {
-+	while ( (opt = getopt(argc, argv, "a:W:s:Ftp:G:P:C:D:N:HBAIXULlSTMRvhcuoimfxrd")) != -1 ) {
-+
- 		switch (opt) {
-+		        case 'a':
-+			        csync_database = optarg;
-+				db_type = DB_MYSQL;
-+				break;
- 			case 'W':
- 				csync_dump_dir_fd = atoi(optarg);
- 				if (write(csync_dump_dir_fd, 0, 0) < 0)
-@@ -314,7 +395,7 @@ int main(int argc, char ** argv)
- 				csync_timestamps = 1;
- 				break;
- 			case 'p':
--				csync_port = atoi(optarg);
-+				csync_port = strdup(optarg);
- 				break;
- 			case 'G':
- 				active_grouplist = optarg;
-@@ -349,6 +430,10 @@ int main(int argc, char ** argv)
- 			case 'v':
- 				csync_debug_level++;
- 				break;
-+			case 'l':
-+				csync_syslog = 1;
-+				openlog("csync2", LOG_ODELAY, LOG_LOCAL0);
-+				break;
- 			case 'h':
- 				if ( mode != MODE_NONE ) help(argv[0]);
- 				mode = MODE_HINT;
-@@ -450,6 +535,13 @@ int main(int argc, char ** argv)
- 	if ( mode == MODE_NONE )
- 		help(argv[0]);
- 
-+	/* Some inetd connect stderr to stdout.  The debug level messages on
-+	 * stderr would confuse the csync2 protocol. Log to syslog instead. */
-+	if ( mode == MODE_INETD && csync_debug_level && !csync_syslog ) {
-+		csync_syslog = 1;
-+		openlog("csync2", LOG_ODELAY, LOG_LOCAL0);
-+	}
-+
- 	if ( *myhostname == 0 ) {
- 		gethostname(myhostname, 256);
- 		myhostname[255] = 0;
-@@ -482,7 +574,7 @@ int main(int argc, char ** argv)
- 		para = cmd ? strtok(0, "\t \r\n") : 0;
- 
- 		if (cmd && !strcasecmp(cmd, "ssl")) {
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- 			conn_printf("OK (activating_ssl).\n");
- 			conn_activate_ssl(1);
- 
-@@ -503,10 +595,8 @@ int main(int argc, char ** argv)
- 		if (para)
- 			cfgname = strdup(url_decode(para));
- 	}
--
- 	if ( !*cfgname ) {
--		asprintf(&file_database, "%s/%s.db", dbdir, myhostname);
--		asprintf(&file_config, ETCDIR "/csync2.cfg");
-+	     ASPRINTF(&file_config, ETCDIR "/csync2.cfg");
- 	} else {
- 		int i;
- 
-@@ -518,14 +608,10 @@ int main(int argc, char ** argv)
- 				return mode != MODE_INETD;
- 			}
- 
--		asprintf(&file_database, "%s/%s_%s.db", dbdir, myhostname, cfgname);
--		asprintf(&file_config, ETCDIR "/csync2_%s.cfg", cfgname);
-+		ASPRINTF(&file_config, ETCDIR "/csync2_%s.cfg", cfgname);
- 	}
- 
--	csync_debug(2, "My hostname is %s.\n", myhostname);
--	csync_debug(2, "Database-File: %s\n", file_database);
- 	csync_debug(2, "Config-File:   %s\n", file_config);
--
- 	yyin = fopen(file_config, "r");
- 	if ( !yyin )
- 		csync_fatal("Can not open config file `%s': %s\n",
-@@ -533,6 +619,12 @@ int main(int argc, char ** argv)
- 	yyparse();
- 	fclose(yyin);
- 
-+	if (!csync_database)
-+		csync_database = db_default_database(dbdir, myhostname, cfgname);
-+
-+	csync_debug(2, "My hostname is %s.\n", myhostname);
-+	csync_debug(2, "Database-File: %s\n", csync_database);
-+
- 	{
- 		const struct csync_group *g;
- 		for (g=csync_group; g; g=g->next)
-@@ -541,7 +633,7 @@ int main(int argc, char ** argv)
- found_a_group:;
- 	}
- 
--	csync_db_open(file_database);
-+	csync_db_open(csync_database);
- 
- 	for (i=optind; i < argc; i++)
- 		on_cygwin_lowercase(argv[i]);
-@@ -582,8 +674,8 @@ found_a_group:;
- 				SQL_BEGIN("Check all hints",
- 					"SELECT filename, recursive FROM hint")
- 				{
--					textlist_add(&tl, url_decode(SQL_V[0]),
--							atoi(SQL_V[1]));
-+					textlist_add(&tl, url_decode(SQL_V(0)),
-+							atoi(SQL_V(1)));
- 				} SQL_END;
- 
- 				for (t = tl; t != 0; t = t->next) {
-@@ -642,51 +734,56 @@ found_a_group:;
- 		case MODE_MARK:
- 			for (i=optind; i < argc; i++) {
- 				char *realname = getrealfn(argv[i]);
-+				char *pfname;
- 				csync_check_usefullness(realname, recursive);
--				csync_mark(realname, 0, 0);
-+				pfname=strdup(prefixencode(realname));
-+				csync_mark(pfname, 0, 0);
- 
- 				if ( recursive ) {
- 					char *where_rec = "";
- 
- 					if ( !strcmp(realname, "/") )
--						asprintf(&where_rec, "or 1");
-+						ASPRINTF(&where_rec, "or 1=1");
- 					else
--						asprintf(&where_rec, "or (filename > '%s/' "
--							"and filename < '%s0')",
--							url_encode(realname), url_encode(realname));
-+						ASPRINTF(&where_rec, "UNION ALL SELECT filename from file where filename > '%s/' "
-+							"and filename < '%s0'",
-+							url_encode(pfname), url_encode(pfname));
- 
- 					SQL_BEGIN("Adding dirty entries recursively",
- 						"SELECT filename FROM file WHERE filename = '%s' %s",
--						url_encode(realname), where_rec)
-+						url_encode(pfname), where_rec)
- 					{
--						char *filename = strdup(url_encode(SQL_V[0]));
-+						char *filename = strdup(url_decode(SQL_V(0)));
- 						csync_mark(filename, 0, 0);
- 						free(filename);
- 					} SQL_END;
- 				}
-+				free(pfname);
- 			}
- 			break;
- 
- 		case MODE_FORCE:
- 			for (i=optind; i < argc; i++) {
- 				char *realname = getrealfn(argv[i]);
-+				char *pfname = strdup(prefixencode(realname));
- 				char *where_rec = "";
- 
- 				if ( recursive ) {
- 					if ( !strcmp(realname, "/") )
--						asprintf(&where_rec, "or 1");
-+						ASPRINTF(&where_rec, "or 1=1");
- 					else
--						asprintf(&where_rec, "or (filename > '%s/' "
-+						ASPRINTF(&where_rec, "or (filename > '%s/' "
- 							"and filename < '%s0')",
- 							url_encode(realname), url_encode(realname));
- 				}
- 
- 				SQL("Mark file as to be forced",
--					"UPDATE dirty SET force = 1 WHERE filename = '%s' %s",
-+					"UPDATE dirty SET forced = 1 WHERE filename = '%s' %s",
- 					url_encode(realname), where_rec);
- 
- 				if ( recursive )
- 					free(where_rec);
-+				free(pfname);
- 			}
- 			break;
- 
-@@ -695,7 +792,7 @@ found_a_group:;
- 			SQL_BEGIN("DB Dump - Hint",
- 				"SELECT recursive, filename FROM hint ORDER BY filename")
- 			{
--				printf("%s\t%s\n", SQL_V[0], url_decode(SQL_V[1]));
-+				printf("%s\t%s\n", (char*)SQL_V(0), url_decode(SQL_V(1)));
- 				retval = -1;
- 			} SQL_END;
- 			break;
-@@ -705,8 +802,8 @@ found_a_group:;
- 			SQL_BEGIN("DB Dump - File",
- 				"SELECT checktxt, filename FROM file ORDER BY filename")
- 			{
--				if (csync_find_next(0, url_decode(SQL_V[1]))) {
--					printf("%s\t%s\n", url_decode(SQL_V[0]), url_decode(SQL_V[1]));
-+				if (csync_find_next(0, url_decode(SQL_V(1)))) {
-+					printf("%s\t%s\n", url_decode(SQL_V(0)), url_decode(SQL_V(1)));
- 					retval = -1;
- 				}
- 			} SQL_END;
-@@ -717,8 +814,8 @@ found_a_group:;
- 			SQL_BEGIN("DB Dump - File",
- 				"SELECT checktxt, filename FROM file ORDER BY filename")
- 			{
--				if ( csync_match_file_host(url_decode(SQL_V[1]), argv[optind], argv[optind+1], 0) ) {
--					printf("%s\t%s\n", url_decode(SQL_V[0]), url_decode(SQL_V[1]));
-+				if ( csync_match_file_host(url_decode(SQL_V(1)), argv[optind], argv[optind+1], 0) ) {
-+					printf("%s\t%s\n", url_decode(SQL_V(0)), url_decode(SQL_V(1)));
- 					retval = -1;
- 				}
- 			} SQL_END;
-@@ -767,11 +864,11 @@ found_a_group:;
- 		case MODE_LIST_DIRTY:
- 			retval = 2;
- 			SQL_BEGIN("DB Dump - Dirty",
--				"SELECT force, myname, peername, filename FROM dirty ORDER BY filename")
-+				"SELECT forced, myname, peername, filename FROM dirty ORDER BY filename")
- 			{
--				if (csync_find_next(0, url_decode(SQL_V[3]))) {
--					printf("%s\t%s\t%s\t%s\n", atoi(SQL_V[0]) ?  "force" : "chary",
--						url_decode(SQL_V[1]), url_decode(SQL_V[2]), url_decode(SQL_V[3]));
-+				if (csync_find_next(0, url_decode(SQL_V(3)))) {
-+					printf("%s\t%s\t%s\t%s\n", atoi(SQL_V(0)) ?  "force" : "chary",
-+						url_decode(SQL_V(1)), url_decode(SQL_V(2)), url_decode(SQL_V(3)));
- 					retval = -1;
- 				}
- 			} SQL_END;
-diff --git a/csync2.cfg b/csync2.cfg
-index 338bb7b..ff9e639 100644
---- a/csync2.cfg
-+++ b/csync2.cfg
-@@ -1,4 +1,3 @@
--
- # Csync2 Example Configuration File
- # ---------------------------------
- #
-@@ -12,6 +11,22 @@
- #
- # 	key /etc/csync2.key_mygroup;
- #
-+# 	#
-+# 	# WARNING:
-+# 	# You CANNOT use paths containing a symlink
-+# 	# component in include/exclude options!
-+# 	#
-+# 	# Here is a real-life example:
-+# 	# Suppose you have some 64bit Linux systems
-+# 	# and /usr/lib/ocf is what you want to keep
-+#	# in sync. On 64bit Linux systems, /usr/lib
-+# 	# is usually a symlink to /usr/lib64.
-+# 	# This does not work:
-+# 	#   include /usr/lib/ocf;
-+# 	# But this does work:
-+# 	#   include /usr/lib64/ocf;
-+# 	#
-+# 
- # 	include /etc/apache;
- # 	include %homedir%/bob;
- # 	exclude %homedir%/bob/temp;
-@@ -24,8 +39,12 @@
- # 		exec "/usr/sbin/apache2ctl graceful";
- # 		logfile "/var/log/csync2_action.log";
- # 		do-local;
-+#		# you can use do-local-only if the execution
-+#		# should be done locally only
-+#		# do-local-only;
- # 	}
- #
-+# 	# The backup-directory needs to be created first!
- # 	backup-directory /var/backups/csync2;
- # 	backup-generations 3;
- #
-@@ -37,4 +56,3 @@
- # 	on host[12]: /export/users;
- # 	on *:        /home;
- # }
--
-diff --git a/csync2.h b/csync2.h
-index 1306023..d76f880 100644
---- a/csync2.h
-+++ b/csync2.h
-@@ -21,7 +21,11 @@
- #ifndef CSYNC2_H
- #define CSYNC2_H 1
- 
-+#define CSYNC2_VERSION "2.0-rc1"
-+
-+#ifndef _GNU_SOURCE
- #define _GNU_SOURCE
-+#endif
- 
- #include "config.h"
- #include <stdio.h>
-@@ -31,6 +35,24 @@
- #include <errno.h>
- 
- 
-+#define DB_SCHEMA_VERSION 0
-+
-+/* asprintf with test for no memory */
-+
-+#define ASPRINTF(s, fmt, ...) do {\
-+	int __ret = asprintf(s, fmt, ##__VA_ARGS__);\
-+	if (__ret < 0) \
-+		csync_fatal("Out of memory in asprintf at %s:%d\n", __FILE__, __LINE__);\
-+} while (0)
-+
-+
-+#define VASPRINTF(s, fmt, args) do {\
-+	int __ret = vasprintf(s, fmt, args);\
-+	if (__ret < 0) \
-+		csync_fatal("Out of memory in vasprintf at %s:%d\n", __FILE__, __LINE__);\
-+} while (0)
-+
-+
- /* action.c */
- 
- extern void csync_schedule_commands(const char *filename, int islocal);
-@@ -78,7 +100,7 @@ extern int conn_write(const void *buf, size_t count);
- 
- extern void conn_printf(const char *fmt, ...);
- extern int conn_fgets(char *s, int size);
--extern int conn_gets(char *s, int size);
-+extern size_t conn_gets(char *s, size_t size);
- 
- 
- /* db.c */
-@@ -91,26 +113,56 @@ extern void* csync_db_begin(const char *err, const char *fmt, ...);
- extern int csync_db_next(void *vmx, const char *err,
- 		int *pN, const char ***pazValue, const char ***pazColName);
- extern void csync_db_fin(void *vmx, const char *err);
-+extern const void * csync_db_colblob(void *stmtx,int col);
-+extern char *db_default_database(char *dbdir, char *myhostname, char *cfg_name);
-+
- 
- #define SQL(e, s, ...) csync_db_sql(e, s, ##__VA_ARGS__)
- 
-+#if 0
-+#if defined(HAVE_LIBSQLITE)
- #define SQL_BEGIN(e, s, ...) \
- { \
- 	char *SQL_ERR = e; \
- 	void *SQL_VM = csync_db_begin(SQL_ERR, s, ##__VA_ARGS__); \
- 	int SQL_COUNT = 0; \
- 	while (1) { \
--		const char **SQL_V, **SQL_N; \
-+		const char **dataSQL_V, **dataSQL_N; \
- 		int SQL_C; \
- 		if ( !csync_db_next(SQL_VM, SQL_ERR, \
--					&SQL_C, &SQL_V, &SQL_N) ) break; \
-+					&SQL_C, &dataSQL_V, &dataSQL_N) ) break; \
- 		SQL_COUNT++;
- 
-+#define SQL_V(col) \
-+	(dataSQL_V[(col)])
-+#endif
-+#endif
-+
-+// #if defined(HAVE_LIBSQLITE3)
-+
-+#define SQL_BEGIN(e, s, ...) \
-+{ \
-+	char *SQL_ERR = e; \
-+	void *SQL_VM = csync_db_begin(SQL_ERR, s, ##__VA_ARGS__); \
-+	int SQL_COUNT = 0; \
-+\
-+	if (SQL_VM) { \
-+		while (1) { \
-+			const char **dataSQL_V, **dataSQL_N; \
-+			int SQL_C; \
-+			if ( !csync_db_next(SQL_VM, SQL_ERR, \
-+						&SQL_C, &dataSQL_V, &dataSQL_N) ) break; \
-+			SQL_COUNT++;
-+
-+#define SQL_V(col) \
-+	(csync_db_colblob(SQL_VM,(col)))
-+// #endif
- #define SQL_FIN }{
- 
- #define SQL_END \
-+		} \
-+		csync_db_fin(SQL_VM, SQL_ERR); \
- 	} \
--	csync_db_fin(SQL_VM, SQL_ERR); \
- }
- 
- extern int db_blocking_mode;
-@@ -150,6 +202,7 @@ extern void csync_remove_old();
- /* daemon.c */
- 
- extern void csync_daemon_session();
-+extern int csync_copy_file(int fd_in, int fd_out);
- 
- 
- /* getrealfn.c */
-@@ -170,6 +223,7 @@ const char *url_decode(const char *in);
- 
- /* another ringbuffer here. so use it with care!! */
- const char *prefixsubst(const char *in);
-+const char *prefixencode(const char *filename);
- 
- 
- /* textlist implementation */
-@@ -233,12 +287,13 @@ struct csync_group_host {
- 
- struct csync_group_pattern {
- 	struct csync_group_pattern *next;
--	int isinclude, iscompare;
-+	int isinclude, iscompare, star_matches_slashes;
- 	const char *pattern;
- };
- 
- struct csync_group_action_pattern {
- 	struct csync_group_action_pattern *next;
-+	int star_matches_slashes;
- 	const char *pattern;
- };
- 
-@@ -253,6 +308,7 @@ struct csync_group_action {
- 	struct csync_group_action_command *command;
- 	const char *logfile;
- 	int do_local;
-+	int do_local_only;
- };
- 
- struct csync_group {
-@@ -301,8 +357,14 @@ extern struct csync_group  *csync_group;
- extern struct csync_prefix *csync_prefix;
- extern struct csync_nossl  *csync_nossl;
- 
-+extern unsigned csync_lock_timeout;
-+extern char *csync_tempdir;
-+
-+extern char *csync_database;
-+
- extern int csync_error_count;
- extern int csync_debug_level;
-+extern int csync_syslog;
- extern FILE *csync_debug_out;
- 
- extern long csync_last_printtime;
-@@ -312,9 +374,9 @@ extern int csync_messages_printed;
- extern int csync_server_child_pid;
- extern int csync_timestamps;
- extern int csync_new_force;
--extern int csync_port;
- 
- extern char myhostname[];
-+extern char *csync_port;
- extern char *active_grouplist;
- extern char *active_peerlist;
- 
-@@ -328,7 +390,7 @@ extern int csync_dump_dir_fd;
- 
- extern int csync_compare_mode;
- 
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- extern int csync_conn_usessl;
- #endif
- 
-diff --git a/csync2.spec b/csync2.spec
-index 17daad6..5d342dc 100644
---- a/csync2.spec
-+++ b/csync2.spec
-@@ -23,15 +23,15 @@
- # norootforbuild
- # neededforbuild  openssl openssl-devel
- 
--BuildRequires: sqlite-devel sqlite librsync openssl-devel librsync-devel
-+BuildRequires: sqlite-devel sqlite librsync gnutls-devel librsync-devel
- 
- Name:         csync2
- License:      GPL
- Group:        System/Monitoring
- Requires:     sqlite openssl librsync
- Autoreqprov:  on
--Version:      1.34
--Release:      1
-+Version:      2.0
-+Release:      0.1.rc1
- Source0:      csync2-%{version}.tar.gz
- URL:          http://oss.linbit.com/csync2
- BuildRoot:    %{_tmppath}/%{name}-%{version}-build
-@@ -83,6 +83,7 @@ fi
- %defattr(-,root,root)
- %doc ChangeLog README NEWS INSTALL TODO AUTHORS
- %{_sbindir}/csync2
-+%{_sbindir}/csync2-compare
- %{_var}/lib/csync2
- %{_mandir}/man1/csync2.1.gz
- %config(noreplace) %{_sysconfdir}/xinetd.d/csync2
-diff --git a/daemon.c b/daemon.c
-index a6357fa..2c054ed 100644
---- a/daemon.c
-+++ b/daemon.c
-@@ -23,6 +23,7 @@
- #include <sys/stat.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
-+#include <arpa/inet.h>
- #include <string.h>
- #include <fnmatch.h>
- #include <stdlib.h>
-@@ -38,6 +39,9 @@
- 
- static char *cmd_error;
- 
-+int csync_setBackupFileStatus(char *filename, int backupDirLength);
-+
-+
- int csync_unlink(const char *filename, int ign)
- {
- 	struct stat st;
-@@ -80,8 +84,13 @@ void csync_file_update(const char *filename, const char *peername)
- 			url_encode(filename));
- 	} else {
- 		const char *checktxt = csync_genchecktxt(&st, filename, 0);
-+
-+		SQL("Deleting old record from file db",
-+			"DELETE FROM file WHERE filename = '%s'",
-+			url_encode(filename));
-+
- 		SQL("Insert record to file db",
--			"insert into file (filename, checktxt) values "
-+			"INSERT INTO file (filename, checktxt) values "
- 			"('%s', '%s')", url_encode(filename),
- 			url_encode(checktxt));
- 	}
-@@ -98,73 +107,164 @@ int csync_file_backup(const char *filename)
- {
- 	static char error_buffer[1024];
- 	const struct csync_group *g = NULL;
-+	struct stat buf;
-+	int rc;
- 	while ( (g=csync_find_next(g, filename)) ) {
--		if (g->backup_directory && g->backup_generations > 0) {
--			int bak_dir_len = strlen(g->backup_directory);
--			int filename_len = strlen(filename);
--			char backup_filename[bak_dir_len + filename_len + 10];
--			char backup_otherfilename[bak_dir_len + filename_len + 10];
--			int fd_in, fd_out, i;
--
--			fd_in = open(filename, O_RDONLY);
--			if (fd_in < 0) return 0;
--
--			memcpy(backup_filename, g->backup_directory, bak_dir_len);
--			for (i=0; i<filename_len; i++)
--				backup_filename[bak_dir_len+i] =
--					filename[i] == '/' ? '_' : filename[i];
--			backup_filename[bak_dir_len] = '/';
--			memcpy(backup_otherfilename, backup_filename,
--					bak_dir_len + filename_len);
--
--			for (i=g->backup_generations-1; i; i--) {
--				snprintf(backup_filename+bak_dir_len+filename_len, 10, ".%d", i-1);
--				snprintf(backup_otherfilename+bak_dir_len+filename_len, 10, ".%d", i);
--				rename(backup_filename, backup_otherfilename);
--			}
--
--			strcpy(backup_filename+bak_dir_len+filename_len, ".0");
--			fd_out = open(backup_filename, O_WRONLY|O_CREAT, 0600);
--
--			if (fd_out < 0) {
--				snprintf(error_buffer, 1024,
--						"Open error while backing up '%s': %s\n",
--						filename, strerror(errno));
--				cmd_error = error_buffer;
--				close(fd_in);
--				return 1;
--			}
--
--			while (1) {
--				char buffer[512];
--				int read_len = read(fd_in, buffer, 512);
--				int write_len = 0;
--
--				if (read_len <= 0)
--					break;
--
--				while (write_len < read_len) {
--					int rc = write(fd_out, buffer+write_len, read_len-write_len);
--					if (rc <= 0) {
--						snprintf(error_buffer, 1024,
--								"Write error while backing up '%s': %s\n",
--								filename, strerror(errno));
--						cmd_error = error_buffer;
--						close(fd_in);
--						close(fd_out);
--						return 1;
--					}
--					write_len += rc;
--				}
--			}
--			close(fd_in);
--			close(fd_out);
--		}
-+	  if (g->backup_directory && g->backup_generations > 1) {
-+	    
-+	    int bak_dir_len = strlen(g->backup_directory);
-+	    int filename_len = strlen(filename);
-+	    char backup_filename[bak_dir_len + filename_len + 10];
-+	    char backup_otherfilename[bak_dir_len + filename_len + 10];
-+	    int fd_in, fd_out, i;
-+	    int lastSlash = 0;
-+	    mode_t mode;
-+	    csync_debug(1, "backup\n");
-+	    // Skip generation of directories
-+	    rc =  stat(filename, &buf);
-+	    if (S_ISDIR(buf.st_mode)) {
-+	      csync_debug(1, "directory. Skip generation \n");
-+	      return 0;
-+	    }
-+
-+	    fd_in = open(filename, O_RDONLY);
-+	    if (fd_in < 0) 
-+	      return 0;
-+			
-+	    memcpy(backup_filename, g->backup_directory, bak_dir_len);
-+	    backup_filename[bak_dir_len] = 0;
-+	    mode = 0777;
-+
-+
-+	    for (i=filename_len; i> 0; i--)
-+	      if (filename[i] == '/')  {
-+		lastSlash = i;
-+		break;
-+	      }
-+			
-+	    for (i=0; i < filename_len; i++) {
-+		// Create directories in filename
-+		// TODO: Get the mode from the orig. dir
-+	      if (filename[i] == '/' && i <= lastSlash) {
-+
-+		backup_filename[bak_dir_len+i] = 0;
-+
-+		csync_debug(1, "mkdir %s \n", backup_filename);
-+
-+		mkdir(backup_filename, mode);
-+		// Dont check the empty string.
-+		if (i!= 0)
-+		  csync_setBackupFileStatus(backup_filename, bak_dir_len);
-+
-+	      }
-+		backup_filename[bak_dir_len+i] = filename[i];
-+	    }
-+
-+	    backup_filename[bak_dir_len + filename_len] = 0;
-+	    backup_filename[bak_dir_len] = '/';
-+	    memcpy(backup_otherfilename, backup_filename,
-+		   bak_dir_len + filename_len);
-+	    
-+	    //rc = unlink(
-+	    for (i=g->backup_generations-1; i; i--) {
-+
-+	      if (i != 1)
-+		snprintf(backup_filename+bak_dir_len+filename_len, 10, ".%d", i-1);
-+	      backup_filename[bak_dir_len+filename_len] = '\0';
-+	      snprintf(backup_otherfilename+bak_dir_len+filename_len, 10, ".%d", i);
-+
-+	      rc = rename(backup_filename, backup_otherfilename);
-+	      csync_debug(1, "renaming backup files '%s' to '%s'. rc = %d\n", backup_filename, backup_otherfilename, rc);
-+	      
-+	    }
-+
-+	    /* strcpy(backup_filename+bak_dir_len+filename_len, ""); */
-+
-+	    fd_out = open(backup_filename, O_WRONLY|O_CREAT, 0600);
-+
-+	    if (fd_out < 0) {
-+	      snprintf(error_buffer, 1024,
-+		       "Open error while backing up '%s': %s\n",
-+		       filename, strerror(errno));
-+	      cmd_error = error_buffer;
-+	      close(fd_in);
-+	      return 1;
-+	    }
-+
-+	    csync_debug(1,"Copying data from %s to backup file %s \n", filename, backup_filename);
-+
-+	    rc  = csync_copy_file(fd_in, fd_out);
-+	    if (rc != 0) {
-+		csync_debug(1, "csync_backup error 2\n");
-+
-+		snprintf(error_buffer, 1024,
-+			 "Write error while backing up '%s': %s\n",
-+			 filename, strerror(errno));
-+
-+		cmd_error = error_buffer;
-+		// TODO verify file disapeared ? 
-+		// 
-+		// return 1;
-+	    }
-+	    csync_setBackupFileStatus(backup_filename, bak_dir_len);
-+	    csync_debug(1, "csync_backup loop end\n");
-+	  }
- 	}
--
-+	csync_debug(1, "csync_backup end\n");
- 	return 0;
- }
- 
-+int csync_copy_file(int fd_in, int fd_out) 
-+{
-+  char buffer[512];
-+  int read_len = read(fd_in, buffer, 512);
-+
-+  while (read_len > 0) {
-+    int write_len = 0;
-+    
-+    while (write_len < read_len) {
-+      int rc = write(fd_out, buffer+write_len, read_len-write_len);
-+      if (rc == -1) {
-+	close(fd_in);
-+	close(fd_out);
-+	//TODO verify return code. 
-+	return errno;
-+      }
-+      write_len += rc;
-+    }
-+    read_len = read(fd_in, buffer, 512);
-+  }	
-+  close(fd_in);
-+  close(fd_out);
-+  return 0;
-+}
-+
-+/* get the mode from the orig directory.
-+   Looking from the back_dir_len should produce the original dir.
-+*/
-+int csync_setBackupFileStatus(char *filename, int backupDirLength) {
-+
-+  struct stat buf;
-+  int rc = stat((filename + backupDirLength), &buf);
-+  if (rc == 0 ) {
-+    csync_debug(0, "Stating original file %s rc: %d mode: %o", (filename + backupDirLength), rc, buf.st_mode);
-+
-+    rc = chown(filename, buf.st_uid, buf.st_gid);
-+    csync_debug(0, "Changing owner of %s to user %d and group %d, rc= %d \n", 
-+		filename, buf.st_uid, buf.st_gid, rc);
-+
-+    rc = chmod(filename, buf.st_mode);
-+    csync_debug(0, "Changing mode of %s to mode %d, rc= %d \n", 
-+		filename, buf.st_mode, rc);
-+
-+  }
-+  else {
-+    csync_debug(0, "Error getting mode and owner ship from %s \n", (filename + backupDirLength));
-+    return -1;
-+  }
-+  return 0;
-+};
-+
- struct csync_command {
- 	char *text;
- 	int check_perm;
-@@ -210,16 +310,149 @@ struct csync_command cmdtab[] = {
- 	{ 0,		0, 0, 0, 0, 0, 0	}
- };
- 
-+typedef union address {
-+	struct sockaddr sa;
-+	struct sockaddr_in sa_in;
-+	struct sockaddr_in6 sa_in6;
-+	struct sockaddr_storage ss;
-+} address_t;
-+
-+const char *csync_inet_ntop(address_t *addr)
-+{
-+	char buf[INET6_ADDRSTRLEN];
-+	sa_family_t af = addr->sa.sa_family;
-+	return inet_ntop(af,
-+		af == AF_INET  ? (void*)&addr->sa_in.sin_addr :
-+		af == AF_INET6 ? (void*)&addr->sa_in6.sin6_addr : NULL,
-+		buf, sizeof(buf));
-+}
-+
-+/*
-+ * Loops (to cater for multihomed peers) through the address list returned by
-+ * gethostbyname(), returns 1 if any match with the address obtained from
-+ * getpeername() during session startup.
-+ * Otherwise returns 0 (-> identification failed).
-+ *
-+ * TODO switch to a getnameinfo in conn_open.
-+ * TODO add a "pre-authenticated" pipe mode for use over ssh */
-+int verify_peername(const char *name, address_t *peeraddr)
-+{
-+	sa_family_t af = peeraddr->sa.sa_family;
-+	struct addrinfo hints;
-+	struct addrinfo *result, *rp;
-+	int try_mapped_ipv4;
-+	int s;
-+
-+	/* Obtain address(es) matching host */
-+	memset(&hints, 0, sizeof(struct addrinfo));
-+	hints.ai_family = AF_UNSPEC;     /* Allow IPv4 or IPv6 */
-+	hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
-+
-+	s = getaddrinfo(name, NULL, &hints, &result);
-+	if (s != 0) {
-+		csync_debug(1, "getaddrinfo: %s\n", gai_strerror(s));
-+		return 0;
-+	}
-+
-+	try_mapped_ipv4 =
-+		af == AF_INET6 &&
-+		!memcmp(&peeraddr->sa_in6.sin6_addr,
-+			"\0\0\0\0" "\0\0\0\0" "\0\0\xff\xff", 12);
-+
-+	/* getaddrinfo() returns a list of address structures.
-+	 * Try each address. */
-+
-+	for (rp = result; rp != NULL; rp = rp->ai_next) {
-+		/* both IPv4 */
-+		if (af == AF_INET && rp->ai_family == AF_INET &&
-+		    !memcmp(&((struct sockaddr_in*)rp->ai_addr)->sin_addr,
-+			    &peeraddr->sa_in.sin_addr, sizeof(struct in_addr)))
-+			break;
-+		/* both IPv6 */
-+		if (af == AF_INET6 && rp->ai_family == AF_INET6 &&
-+		    !memcmp(&((struct sockaddr_in6*)rp->ai_addr)->sin6_addr,
-+			    &peeraddr->sa_in6.sin6_addr, sizeof(struct in6_addr)))
-+			break;
-+		/* peeraddr IPv6, but actually ::ffff:I.P.v.4,
-+		 * and forward lookup returned IPv4 only */
-+		if (af == AF_INET6 && rp->ai_family == AF_INET &&
-+		    try_mapped_ipv4 &&
-+		    !memcmp(&((struct sockaddr_in*)rp->ai_addr)->sin_addr,
-+			    (unsigned char*)&peeraddr->sa_in6.sin6_addr + 12,
-+			    sizeof(struct in_addr)))
-+			break;
-+	}
-+	freeaddrinfo(result);
-+	if (rp != NULL) /* memcmp found a match */
-+		return conn_check_peer_cert(name, 0);
-+	return 0;
-+}
-+
-+/* Why do all this fuzz, and not simply --assume-authenticated?
-+ * To limit the impact of an accidental misconfiguration.
-+ */
-+void set_peername_from_env(address_t *p, const char *env)
-+{
-+	struct addrinfo hints = {
-+		.ai_family = AF_UNSPEC,
-+		.ai_socktype = SOCK_STREAM,
-+		.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV,
-+	};
-+	struct addrinfo *result;
-+	char *c;
-+	int s;
-+
-+	char *val = getenv(env);
-+	csync_debug(3, "getenv(%s): >>%s<<\n", env, val ?: "");
-+	if (!val)
-+		return;
-+	val = strdup(val);
-+	if (!val)
-+		return;
-+
-+	c = strchr(val, ' ');
-+	if (!c)
-+		return;
-+	*c = '\0';
-+
-+	s = getaddrinfo(val, NULL, &hints, &result);
-+	if (s != 0) {
-+		csync_debug(1, "getaddrinfo: %s\n", gai_strerror(s));
-+		return;
-+	}
-+
-+	/* getaddrinfo() may return a list of address structures.
-+	 * Use the first one. */
-+	if (result)
-+		memcpy(p, result->ai_addr, result->ai_addrlen);
-+	freeaddrinfo(result);
-+}
-+
- void csync_daemon_session()
- {
--	struct sockaddr_in peername;
--	struct hostent *hp;
--	int peerlen = sizeof(struct sockaddr_in);
-+	struct stat sb;
-+	address_t peername = { .sa.sa_family = AF_UNSPEC, };
-+	socklen_t peerlen = sizeof(peername);
- 	char line[4096], *peer=0, *tag[32];
- 	int i;
- 
--	if ( getpeername(0, (struct sockaddr*)&peername, &peerlen) == -1 )
--		csync_fatal("Can't run getpeername on fd 0: %s", strerror(errno));
-+
-+	if (fstat(0, &sb))
-+		csync_fatal("Can't run fstat on fd 0: %s", strerror(errno));
-+
-+	switch (sb.st_mode & S_IFMT) {
-+	case S_IFSOCK:
-+		if ( getpeername(0, &peername.sa, &peerlen) == -1 )
-+			csync_fatal("Can't run getpeername on fd 0: %s", strerror(errno));
-+		break;
-+	case S_IFIFO:
-+		set_peername_from_env(&peername, "SSH_CLIENT");
-+		break;
-+		/* fall through */
-+	default:
-+		csync_fatal("I'm only talking to sockets or pipes! %x\n", sb.st_mode & S_IFMT);
-+		break;
-+	}
- 
- 	while ( conn_gets(line, 4096) ) {
- 		int cmdnr;
-@@ -246,13 +479,8 @@ void csync_daemon_session()
- 		cmd_error = 0;
- 
- 		if ( cmdtab[cmdnr].need_ident && !peer ) {
--			union {
--				in_addr_t addr;
--				unsigned char oct[4];
--			} tmp;
--			tmp.addr = peername.sin_addr.s_addr;
--			conn_printf("Dear %d.%d.%d.%d, please identify first.\n",
--					tmp.oct[0], tmp.oct[1], tmp.oct[2], tmp.oct[3]);
-+			conn_printf("Dear %s, please identify first.\n",
-+				    csync_inet_ntop(&peername) ?: "stranger");
- 			goto next_cmd;
- 		}
- 
-@@ -443,8 +671,8 @@ void csync_daemon_session()
- 					strcmp(tag[2], "-") ? url_encode(tag[2]) : "",
- 					strcmp(tag[2], "-") ? "'" : "")
- 			{
--				if ( csync_match_file_host(url_decode(SQL_V[1]), tag[1], peer, (const char **)&tag[3]) )
--					conn_printf("%s\t%s\n", SQL_V[0], SQL_V[1]);
-+				if ( csync_match_file_host(url_decode(SQL_V(1)), tag[1], peer, (const char **)&tag[3]) )
-+					conn_printf("%s\t%s\n", SQL_V(0), SQL_V(1));
- 			} SQL_END;
- 			break;
- 
-@@ -454,18 +682,18 @@ void csync_daemon_session()
- 				csync_debug_level = atoi(tag[1]);
- 			break;
- 		case A_HELLO:
--			if (peer) free(peer);
--			hp = gethostbyname(tag[1]);
--			if ( hp != 0 && peername.sin_family == hp->h_addrtype &&
--			     !memcmp(hp->h_addr, &peername.sin_addr, hp->h_length) &&
--			     conn_check_peer_cert(tag[1], 0)) {
-+			if (peer) {
-+				free(peer);
-+				peer = NULL;
-+			}
-+			if (verify_peername(tag[1], &peername)) {
- 				peer = strdup(tag[1]);
- 			} else {
--				peer = 0;
-+				peer = NULL;
- 				cmd_error = "Identification failed!";
- 				break;
- 			}
--#ifdef HAVE_LIBGNUTLS_OPENSSL
-+#ifdef HAVE_LIBGNUTLS
- 			if (!csync_conn_usessl) {
- 				struct csync_nossl *t;
- 				for (t = csync_nossl; t; t=t->next) {
-@@ -507,7 +735,7 @@ found_asactive: ;
- 			break;
- 		case A_BYE:
- 			for (i=0; i<32; i++)
--				tag[i] = strdup(url_decode(tag[i]));
-+				free(tag[i]);
- 			conn_printf("OK (cu_later).\n");
- 			return;
- 		}
-@@ -529,7 +757,6 @@ abort_cmd:
- 
- next_cmd:
- 		for (i=0; i<32; i++)
--			tag[i] = strdup(url_decode(tag[i]));
-+			free(tag[i]);
- 	}
- }
--
-diff --git a/db.c b/db.c
-index 1cd6953..68848b3 100644
---- a/db.c
-+++ b/db.c
-@@ -19,13 +19,13 @@
-  */
- 
- #include "csync2.h"
--#include <sqlite.h>
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <signal.h>
- #include <time.h>
-+#include "db_api.h"
- 
- #define DEADLOCK_MESSAGE \
- 	"Database backend is exceedingly busy => Terminating (requesting retry).\n"
-@@ -33,14 +33,16 @@
- int db_blocking_mode = 1;
- int db_sync_mode = 1;
- 
--static sqlite *db = 0;
-+extern int db_type; 
-+static db_conn_p db = 0;
-+// TODO make configurable
-+int wait = 1;
- 
- static int get_dblock_timeout()
- {
--	return getpid() % 7 + 12;
-+	return getpid() % 7 + csync_lock_timeout;
- }
- 
--
- static int tqueries_counter = -50;
- static time_t transaction_begin = 0;
- static time_t last_wait_cycle = 0;
-@@ -58,7 +60,7 @@ void csync_db_alarmhandler(int signum)
- 	begin_commit_recursion++;
- 
- 	csync_debug(2, "Database idle in transaction. Forcing COMMIT.\n");
--	SQL("COMMIT TRANSACTION", "COMMIT TRANSACTION");
-+	SQL("COMMIT ", "COMMIT ");
- 	tqueries_counter = -10;
- 
- 	begin_commit_recursion--;
-@@ -82,7 +84,7 @@ void csync_db_maybegin()
- 		transaction_begin = time(0);
- 		if (!last_wait_cycle)
- 			last_wait_cycle = transaction_begin;
--		SQL("BEGIN TRANSACTION", "BEGIN TRANSACTION");
-+		SQL("BEGIN ", "BEGIN ");
- 	}
- 
- 	begin_commit_recursion--;
-@@ -103,9 +105,11 @@ void csync_db_maycommit()
- 	now = time(0);
- 
- 	if ((now - last_wait_cycle) > 10) {
--		SQL("COMMIT TRANSACTION", "COMMIT TRANSACTION");
--		csync_debug(2, "Waiting 2 secs so others can lock the database (%d - %d)...\n", (int)now, (int)last_wait_cycle);
--		sleep(2);
-+		SQL("COMMIT", "COMMIT ");
-+		if (wait) {
-+		  csync_debug(2, "Waiting %d secs so others can lock the database (%d - %d)...\n", wait, (int)now, (int)last_wait_cycle);
-+		  sleep(wait);
-+		}
- 		last_wait_cycle = 0;
- 		tqueries_counter = -10;
- 		begin_commit_recursion--;
-@@ -113,7 +117,7 @@ void csync_db_maycommit()
- 	}
- 
- 	if ((tqueries_counter > 1000) || ((now - transaction_begin) > 3)) {
--		SQL("COMMIT TRANSACTION", "COMMIT TRANSACTION");
-+	        SQL("COMMIT ", "COMMIT ");
- 		tqueries_counter = 0;
- 		begin_commit_recursion--;
- 		return;
-@@ -128,45 +132,23 @@ void csync_db_maycommit()
- 
- void csync_db_open(const char *file)
- {
--	db = sqlite_open(file, 0, 0);
--	if ( db == 0 )
-+        int rc = db_open(file, db_type, &db);
-+	if ( rc != DB_OK )
- 		csync_fatal("Can't open database: %s\n", file);
- 
-+	db_set_logger(db, csync_debug);
-+
- 	/* ignore errors on table creation */
- 	in_sql_query++;
--	sqlite_exec(db,
--		"CREATE TABLE file ("
--		"	filename, checktxt,"
--		"	UNIQUE ( filename ) ON CONFLICT REPLACE"
--		")",
--		0, 0, 0);
--	sqlite_exec(db,
--		"CREATE TABLE dirty ("
--		"	filename, force, myname, peername,"
--		"	UNIQUE ( filename, peername ) ON CONFLICT IGNORE"
--		")",
--		0, 0, 0);
--	sqlite_exec(db,
--		"CREATE TABLE hint ("
--		"	filename, recursive,"
--		"	UNIQUE ( filename, recursive ) ON CONFLICT IGNORE"
--		")",
--		0, 0, 0);
--	sqlite_exec(db,
--		"CREATE TABLE action ("
--		"	filename, command, logfile,"
--		"	UNIQUE ( filename, command ) ON CONFLICT IGNORE"
--		")",
--		0, 0, 0);
--	sqlite_exec(db,
--		"CREATE TABLE x509_cert ("
--		"	peername, certdata,"
--		"	UNIQUE ( peername ) ON CONFLICT IGNORE"
--		")",
--		0, 0, 0);
-+
-+	if (db_schema_version(db) < DB_SCHEMA_VERSION)
-+		if (db_upgrade_to_schema(db, DB_SCHEMA_VERSION) != DB_OK)
-+			csync_fatal("Cannot create database tables (version requested = %d): %s\n", DB_SCHEMA_VERSION, db_errmsg(db));
-+
- 	if (!db_sync_mode)
--		sqlite_exec(db, "PRAGMA synchronous = OFF", 0, 0, 0);
-+		db_exec(db, "PRAGMA synchronous = OFF");
- 	in_sql_query--;
-+	// return db;
- }
- 
- void csync_db_close()
-@@ -175,10 +157,10 @@ void csync_db_close()
- 
- 	begin_commit_recursion++;
- 	if (tqueries_counter > 0) {
--		SQL("COMMIT TRANSACTION", "COMMIT TRANSACTION");
-+	        SQL("COMMIT ", "COMMIT ");
- 		tqueries_counter = -10;
- 	}
--	sqlite_close(db);
-+	db_close(db);
- 	begin_commit_recursion--;
- 	db = 0;
- }
-@@ -190,7 +172,7 @@ void csync_db_sql(const char *err, const char *fmt, ...)
- 	int rc, busyc = 0;
- 
- 	va_start(ap, fmt);
--	vasprintf(&sql, fmt, ap);
-+	VASPRINTF(&sql, fmt, ap);
- 	va_end(ap);
- 
- 	in_sql_query++;
-@@ -199,15 +181,15 @@ void csync_db_sql(const char *err, const char *fmt, ...)
- 	csync_debug(2, "SQL: %s\n", sql);
- 
- 	while (1) {
--		rc = sqlite_exec(db, sql, 0, 0, 0);
--		if ( rc != SQLITE_BUSY ) break;
--		if (busyc++ > get_dblock_timeout()) { db = 0; csync_fatal(DEADLOCK_MESSAGE); }
--		csync_debug(2, "Database is busy, sleeping a sec.\n");
--		sleep(1);
-+	  rc = db_exec(db, sql);
-+	  if ( rc != DB_BUSY ) break;
-+	  if (busyc++ > get_dblock_timeout()) { db = 0; csync_fatal(DEADLOCK_MESSAGE); }
-+	  csync_debug(2, "Database is busy, sleeping a sec.\n");
-+	  sleep(1);
- 	}
- 
--	if ( rc != SQLITE_OK && err )
--		csync_fatal("Database Error: %s [%d]: %s\n", err, rc, sql);
-+	if ( rc != DB_OK && err )
-+		csync_fatal("Database Error: %s [%d]: %s on executing %s\n", err, rc, db_errmsg(db), sql);
- 	free(sql);
- 
- 	csync_db_maycommit();
-@@ -216,77 +198,140 @@ void csync_db_sql(const char *err, const char *fmt, ...)
- 
- void* csync_db_begin(const char *err, const char *fmt, ...)
- {
--	sqlite_vm *vm;
-+	db_stmt_p stmt = NULL;
- 	char *sql;
- 	va_list ap;
- 	int rc, busyc = 0;
--
-+	char *ppTail; 
- 	va_start(ap, fmt);
--	vasprintf(&sql, fmt, ap);
-+	VASPRINTF(&sql, fmt, ap);
- 	va_end(ap);
- 
- 	in_sql_query++;
- 	csync_db_maybegin();
- 
- 	csync_debug(2, "SQL: %s\n", sql);
--
- 	while (1) {
--		rc = sqlite_compile(db, sql, 0, &vm, 0);
--		if ( rc != SQLITE_BUSY ) break;
-+	        rc = db_prepare_stmt(db, sql, &stmt, &ppTail);
-+		if ( rc != DB_BUSY ) break;
- 		if (busyc++ > get_dblock_timeout()) { db = 0; csync_fatal(DEADLOCK_MESSAGE); }
- 		csync_debug(2, "Database is busy, sleeping a sec.\n");
- 		sleep(1);
- 	}
- 
--	if ( rc != SQLITE_OK && err )
--		csync_fatal("Database Error: %s [%d]: %s\n", err, rc, sql);
-+	if ( rc != DB_OK && err )
-+		csync_fatal("Database Error: %s [%d]: %s on executing %s\n", err, rc, db_errmsg(db), sql);
- 	free(sql);
- 
--	return vm;
-+	return stmt;
-+}
-+
-+const char *csync_db_get_column_text(void  *stmt, int column) {
-+	return db_stmt_get_column_text(stmt, column);
-+}
-+
-+int csync_db_get_column_int(void *stmt, int column) {
-+  return db_stmt_get_column_int((db_stmt_p) stmt, column);
- }
- 
- int csync_db_next(void *vmx, const char *err,
- 		int *pN, const char ***pazValue, const char ***pazColName)
- {
--	sqlite_vm *vm = vmx;
-+	db_stmt_p stmt = vmx;
- 	int rc, busyc = 0;
- 
- 	csync_debug(4, "Trying to fetch a row from the database.\n");
- 
- 	while (1) {
--		rc = sqlite_step(vm, pN, pazValue, pazColName);
--		if ( rc != SQLITE_BUSY ) break;
--		if (busyc++ > get_dblock_timeout()) { db = 0; csync_fatal(DEADLOCK_MESSAGE); }
-+		rc = db_stmt_next(stmt);
-+		if ( rc != DB_BUSY ) 
-+		  break;
-+		if (busyc++ > get_dblock_timeout()) { 
-+		  db = 0; 
-+		  csync_fatal(DEADLOCK_MESSAGE); 
-+		}
- 		csync_debug(2, "Database is busy, sleeping a sec.\n");
- 		sleep(1);
- 	}
- 
--	if ( rc != SQLITE_OK && rc != SQLITE_ROW &&
--	     rc != SQLITE_DONE && err )
--		csync_fatal("Database Error: %s [%d].\n", err, rc);
-+	if ( rc != DB_OK && rc != DB_ROW &&
-+	     rc != DB_DONE && err )
-+		csync_fatal("Database Error: %s [%d]: %s\n", err, rc, db_errmsg(db));
-+
-+	return rc == DB_ROW;
-+}
- 
--	return rc == SQLITE_ROW;
-+const void * csync_db_colblob(void *stmtx, int col) {
-+       db_stmt_p stmt = stmtx;
-+       const void *ptr = stmt->get_column_blob(stmt, col);
-+       if (stmt->db && stmt->db->logger) {
-+	 stmt->db->logger(4, "DB get blob: %s ", (char *) ptr);
-+       }
-+       return ptr;
- }
- 
- void csync_db_fin(void *vmx, const char *err)
- {
--	sqlite_vm *vm = vmx;
-+        db_stmt_p stmt = (db_stmt_p) vmx;
- 	int rc, busyc = 0;
- 
-+	if (vmx == NULL)
-+	   return;
-+
- 	csync_debug(2, "SQL Query finished.\n");
- 
- 	while (1) {
--		rc = sqlite_finalize(vm, 0);
--		if ( rc != SQLITE_BUSY ) break;
--		if (busyc++ > get_dblock_timeout()) { db = 0; csync_fatal(DEADLOCK_MESSAGE); }
--		csync_debug(2, "Database is busy, sleeping a sec.\n");
--		sleep(1);
-+	  rc = db_stmt_close(stmt);
-+	  if ( rc != DB_BUSY ) 
-+	    break;
-+	  if (busyc++ > get_dblock_timeout()) { db = 0; csync_fatal(DEADLOCK_MESSAGE); }
-+	  csync_debug(2, "Database is busy, sleeping a sec.\n");
-+	  sleep(1);
- 	}
- 
--	if ( rc != SQLITE_OK && err )
--		csync_fatal("Database Error: %s [%d].\n", err, rc);
-+	if ( rc != DB_OK && err )
-+		csync_fatal("Database Error: %s [%d]: %s\n", err, rc, db_errmsg(db));
- 
- 	csync_db_maycommit();
- 	in_sql_query--;
- }
- 
-+#if defined(HAVE_SQLITE)
-+#define DBEXTENSION ".db"
-+#endif
-+#if defined(HAVE_SQLITE3)
-+#define DBEXTENSION ".db3"
-+#endif
-+
-+char *db_default_database(char *dbdir, char *myhostname, char *cfg_name)
-+{
-+	char *db;
-+
-+#if defined(HAVE_SQLITE3)
-+	if (cfg_name[0] != '\0')
-+		ASPRINTF(&db, "sqlite3://%s/%s_%s" DBEXTENSION, dbdir, myhostname, cfgname);
-+	else
-+		ASPRINTF(&db, "sqlite3://%s/%s" DBEXTENSION, dbdir, myhostname);
-+#elif defined(HAVE_SQLITE)
-+	if (cfg_name[0] != '\0')
-+		ASPRINTF(&db, "sqlite2://%s/%s_%s" DBEXTENSION, dbdir, myhostname, cfgname);
-+	else
-+		ASPRINTF(&db, "sqlite2://%s/%s" DBEXTENSION, dbdir, myhostname);
-+#elif defined(HAVE_MYSQL)
-+	if (cfg_name[0] != '\0')
-+		ASPRINTF(&db, "mysql://root@localhost/csync2_%s_%s" DBEXTENSION, myhostname, cfgname);
-+	else
-+		ASPRINTF(&db, "mysql://root@localhost/csync2_%s" DBEXTENSION, myhostname);
-+
-+#elif defined(HAVE_POSTGRES)
-+	if (cfg_name[0] != '\0')
-+		ASPRINTF(&db, "pgsql://root@localhost/csync2_%s_%s" DBEXTENSION, myhostname, cfgname);
-+	else
-+		ASPRINTF(&db, "pgsql://root@localhost/csync2_%s" DBEXTENSION, myhostname);
-+
-+#else
-+#error "No database backend available. Please install either libpg, libmysqlclient or libsqlite, reconfigure and recompile"
-+#endif
-+
-+	return db;
-+}
-diff --git a/db_api.c b/db_api.c
-new file mode 100644
-index 0000000..af5591c
---- /dev/null
-+++ b/db_api.c
-@@ -0,0 +1,186 @@
-+/*
-+   DB API
-+   
-+ */
-+
-+#include "csync2.h"
-+#include <stdio.h>
-+#include <stdarg.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <signal.h>
-+#include <time.h>
-+#include "db_api.h"
-+
-+#include "db_mysql.h"
-+#include "db_postgres.h"
-+#include "db_sqlite.h"
-+#include "db_sqlite2.h"
-+
-+#define DEADLOCK_MESSAGE \
-+	"Database backend is exceedingly busy => Terminating (requesting retry).\n"
-+
-+int db_sqlite_open(const char *file, db_conn_p *db); 
-+int db_mysql_open(const char *file, db_conn_p *db); 
-+
-+int db_detect_type(const char **db_str, int type) {
-+  const char *db_types[] = { "mysql://", "sqlite3://", "sqlite2://", "pgsql://", 0 };
-+  int types[]            = { DB_MYSQL,   DB_SQLITE3,   DB_SQLITE2,   DB_PGSQL }; 
-+  int index; 
-+  for (index = 0; 1 ; index++) {
-+    if (db_types[index] == 0) 
-+      break;
-+    if (!strncmp(*db_str, db_types[index], strlen(db_types[index]))) {
-+      *db_str += strlen(db_types[index]);
-+      return types[index];
-+    }
-+  }
-+  return type;
-+}
-+
-+int db_open(const char *file, int type, db_conn_p *db)
-+{
-+  int rc = DB_ERROR;
-+  const char *db_str; 
-+  db_str = file; 
-+
-+  type = db_detect_type(&db_str, type);
-+  /* Switch between implementation */
-+  switch (type) {
-+  case DB_SQLITE2:
-+    rc = db_sqlite2_open(db_str, db);
-+
-+    if (rc != DB_OK && db_str[0] != '/')
-+      fprintf(csync_debug_out, "Cannot open database file: %s, maybe you need three slashes (like sqlite:///var/lib/csync2/csync2.db)\n", db_str);
-+    break;
-+  case DB_SQLITE3:
-+    rc = db_sqlite_open(db_str, db);
-+
-+    if (rc != DB_OK && db_str[0] != '/')
-+      fprintf(csync_debug_out, "Cannot open database file: %s, maybe you need three slashes (like sqlite:///var/lib/csync2/csync2.db)\n", db_str);
-+    break;
-+#ifdef HAVE_MYSQL
-+  case DB_MYSQL:
-+    rc = db_mysql_open(db_str, db);
-+    break;
-+#else
-+  case DB_MYSQL:
-+    csync_fatal("No Mysql support configured. Please reconfigure with --enable-mysql (database is %s).\n", file);    
-+    rc = DB_ERROR;
-+    break;
-+#endif
-+#ifdef HAVE_POSTGRES
-+  case DB_PGSQL:
-+    rc = db_postgres_open(db_str, db);
-+    break;
-+#else
-+  case DB_PGSQL:
-+    csync_fatal("No Postgres SQL support configured. Please reconfigure with --enable-postgres (database is %s).\n", file);    
-+    rc = DB_ERROR;
-+    break;
-+#endif
-+
-+  default:
-+    csync_fatal("Database type not found. Can't open database %s\n", file);
-+    rc = DB_ERROR;
-+  }
-+  if (*db)
-+    (*db)->logger = 0;
-+  return rc;
-+}
-+
-+void db_set_logger(db_conn_p conn, void (*logger)(int lv, const char *fmt, ...)) {
-+  if (conn == NULL)
-+    csync_fatal("No connection in set_logger.\n");
-+
-+  conn->logger = logger;
-+}
-+
-+void db_close(db_conn_p conn)
-+{
-+  if (!conn || !conn->close)
-+    return;
-+  conn->close(conn);
-+}
-+
-+const char *db_errmsg(db_conn_p conn)
-+{
-+  if (conn && conn->errmsg)
-+    return conn->errmsg(conn);
-+
-+  return "(no error message function available)";
-+}
-+
-+int db_exec(db_conn_p conn, const char *sql) {
-+  if (conn && conn->exec)
-+    return conn->exec(conn, sql);
-+
-+  csync_debug(0, "No exec function in db_exec.\n");
-+  return DB_ERROR;
-+}
-+
-+int db_prepare_stmt(db_conn_p conn, const char *sql, db_stmt_p *stmt, char **pptail) {
-+  if (conn && conn->prepare)
-+    return conn->prepare(conn, sql, stmt, pptail);
-+
-+  csync_debug(0, "No prepare function in db_prepare_stmt.\n");
-+  return DB_ERROR;
-+}
-+
-+const char *db_stmt_get_column_text(db_stmt_p stmt, int column) {
-+  if (stmt && stmt->get_column_text)
-+    return stmt->get_column_text(stmt, column);
-+
-+  csync_debug(0, "No stmt in db_stmt_get_column_text / no function.\n");
-+  return NULL;
-+}
-+
-+int db_stmt_get_column_int(db_stmt_p stmt, int column) {
-+  if (stmt && stmt->get_column_int)
-+    return stmt->get_column_int(stmt, column);
-+
-+  csync_debug(0, "No stmt in db_stmt_get_column_int / no function.\n");
-+  return 0;
-+}
-+
-+int db_stmt_next(db_stmt_p stmt)
-+{
-+  if (stmt && stmt->next)
-+    return stmt->next(stmt);
-+
-+  csync_debug(0, "No stmt in db_stmt_next / no function.\n");
-+  return DB_ERROR;
-+}
-+
-+int db_stmt_close(db_stmt_p stmt)
-+{
-+  if (stmt && stmt->close)
-+    return stmt->close(stmt);
-+
-+  csync_debug(0, "No stmt in db_stmt_close / no function.\n");
-+  return DB_ERROR;
-+}
-+
-+int db_schema_version(db_conn_p db)
-+{
-+	int version = -1;
-+
-+        SQL_BEGIN(NULL,   /* ignore errors */
-+                "SELECT count(*) from file")
-+        {
-+		version = 0;
-+        } SQL_END;
-+
-+	return version;
-+}
-+
-+
-+int db_upgrade_to_schema(db_conn_p db, int version)
-+{
-+	if (db && db->upgrade_to_schema)
-+		return db->upgrade_to_schema(version);
-+
-+	return DB_ERROR;
-+}
-+
-+
-diff --git a/db_api.h b/db_api.h
-new file mode 100644
-index 0000000..eab627b
---- /dev/null
-+++ b/db_api.h
-@@ -0,0 +1,62 @@
-+
-+#ifndef DB_API_H
-+#define DB_API_H
-+
-+#define DB_SQLITE2 1 
-+#define DB_SQLITE3 2 
-+#define DB_MYSQL   3
-+#define DB_PGSQL   4
-+
-+#define DB_OK                  0
-+#define DB_ERROR               1
-+#define DB_BUSY                2
-+#define DB_NO_CONNECTION       3
-+#define DB_NO_CONNECTION_REAL  4
-+#define DB_ROW  100
-+#define DB_DONE 101
-+
-+typedef struct db_conn_t *db_conn_p;
-+typedef struct db_stmt_t *db_stmt_p;
-+
-+struct db_conn_t {
-+  void *private;
-+  int       (*exec)   (db_conn_p conn, const char* exec);
-+  int       (*prepare)(db_conn_p conn, const char *statement, db_stmt_p *stmt, char **value);
-+  void      (*close)  (db_conn_p conn);
-+  void      (*logger) (int lv, const char *fmt, ...);
-+  const char* (*errmsg) (db_conn_p conn);
-+  int       (*upgrade_to_schema) (int version);
-+};
-+
-+struct db_stmt_t {
-+  void *private;
-+  void *private2;
-+  db_conn_p db;
-+  const char *    (*get_column_text) (db_stmt_p vmx, int column);
-+  const void*     (*get_column_blob) (db_stmt_p vmx, int column);
-+  int             (*get_column_int)  (db_stmt_p vmx, int column);
-+  int       (*next) (db_stmt_p stmt);
-+  int       (*close)(db_stmt_p stmt);
-+};
-+
-+//struct db_conn *db_conn;
-+
-+int       db_open(const char *file, int type, db_conn_p *db);
-+void      db_close(db_conn_p conn);
-+
-+int       db_exec(db_conn_p conn, const char* exec);
-+int       db_exec2(db_conn_p conn, const char* exec, void (*callback)(void *, int, int), void *data, const char **err);
-+
-+int       db_prepare_stmt(db_conn_p conn, const char *statement, db_stmt_p *stmt, char **value);
-+
-+const char *    db_stmt_get_column_text(db_stmt_p stmt, int column);
-+int       db_stmt_get_column_int(db_stmt_p  stmt, int column);
-+int       db_stmt_next (db_stmt_p stmt);
-+int       db_stmt_close(db_stmt_p stmt);
-+
-+void db_set_logger(db_conn_p conn, void (*logger)(int lv, const char *fmt, ...));
-+int db_schema_version(db_conn_p db);
-+int db_upgrade_to_schema(db_conn_p db, int version);
-+const char *db_errmsg(db_conn_p conn);
-+
-+#endif
-diff --git a/db_mysql.c b/db_mysql.c
-new file mode 100644
-index 0000000..1b6d09e
---- /dev/null
-+++ b/db_mysql.c
-@@ -0,0 +1,408 @@
-+/*
-+ *  Copyright (C) 2010  Dennis Schafroth <dennis@schafroth.com>>
-+ *  Copyright (C) 2010  Johannes Thoma <johannes.thoma@gmx.at>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License as published by
-+ *  the Free Software Foundation; either version 2 of the License, or
-+ *  (at your option) any later version.
-+ *
-+ *  This program 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 General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with this program; if not, write to the Free Software
-+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+ */
-+
-+#include "csync2.h"
-+#include <stdio.h>
-+#include <stdarg.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <signal.h>
-+#include <time.h>
-+#include <string.h>
-+#include "db_api.h"
-+#include "db_mysql.h"
-+#include "dl.h"
-+
-+#ifdef HAVE_MYSQL
-+#include <mysql/mysql.h>
-+#include <mysql/mysqld_error.h>
-+
-+static struct db_mysql_fns {
-+	MYSQL *(*mysql_init_fn)(MYSQL*);
-+	MYSQL *(*mysql_real_connect_fn)(MYSQL *, const char *, const char *, const char *, const char *, unsigned int, const char *, unsigned long);
-+	int (*mysql_errno_fn)(MYSQL*);
-+	int (*mysql_query_fn)(MYSQL*, const char*);
-+	void (*mysql_close_fn)(MYSQL*);
-+	const char *(*mysql_error_fn)(MYSQL *);
-+	MYSQL_RES *(*mysql_store_result_fn)(MYSQL *);
-+	unsigned int (*mysql_num_fields_fn)(MYSQL_RES *);
-+	MYSQL_ROW (*mysql_fetch_row_fn)(MYSQL_RES *);
-+	void (*mysql_free_result_fn)(MYSQL_RES *);
-+	unsigned int (*mysql_warning_count_fn)(MYSQL *);
-+} f;
-+
-+static void *dl_handle;
-+
-+
-+static void db_mysql_dlopen(void)
-+{
-+	csync_debug(1, "Opening shared library libmysqlclient.so\n");
-+        dl_handle = dlopen("libmysqlclient.so", RTLD_LAZY);
-+        if (dl_handle == NULL) {
-+                csync_fatal("Could not open libmysqlclient.so: %s\nPlease install Mysql client library (libmysqlclient) or use other database (sqlite, postgres)\n", dlerror());
-+        }
-+
-+	csync_debug(1, "Reading symbols from shared library libmysqlclient.so\n");
-+
-+        LOOKUP_SYMBOL(dl_handle, mysql_init);
-+        LOOKUP_SYMBOL(dl_handle, mysql_real_connect);
-+        LOOKUP_SYMBOL(dl_handle, mysql_errno);
-+        LOOKUP_SYMBOL(dl_handle, mysql_query);
-+        LOOKUP_SYMBOL(dl_handle, mysql_close);
-+        LOOKUP_SYMBOL(dl_handle, mysql_error);
-+        LOOKUP_SYMBOL(dl_handle, mysql_store_result);
-+        LOOKUP_SYMBOL(dl_handle, mysql_num_fields);
-+        LOOKUP_SYMBOL(dl_handle, mysql_fetch_row);
-+        LOOKUP_SYMBOL(dl_handle, mysql_free_result);
-+        LOOKUP_SYMBOL(dl_handle, mysql_warning_count);
-+}
-+
-+
-+int db_mysql_parse_url(char *url, char **host, char **user, char **pass, char **database, unsigned int *port, char **unix_socket) 
-+{
-+  char *pos = strchr(url, '@'); 
-+  if (pos) {
-+    // Optional user/passwd
-+    *(pos) = 0;
-+    *(user) = url;
-+    url = pos + 1;
-+    // TODO password
-+    pos = strchr(*user, ':');
-+    if (pos) {
-+      *(pos) = 0;
-+      *(pass) = (pos +1);
-+    }
-+    else
-+      *pass = 0;
-+  }
-+  else {
-+    // No user/pass password 
-+    *user = 0;
-+    *pass = 0;
-+  }
-+  *host = url;
-+  pos = strchr(*host, '/');
-+  if (pos) {
-+    // Database
-+    (*pos) = 0;
-+    *database = pos+1;
-+  }
-+  else {
-+    *database = 0;
-+  }
-+  pos = strchr(*host, ':');
-+  if (pos) {
-+    (*pos) = 0;
-+    *port = atoi(pos+1);
-+  }
-+  *unix_socket = 0;
-+  return DB_OK;
-+}
-+
-+#endif
-+
-+int db_mysql_open(const char *file, db_conn_p *conn_p)
-+{
-+#ifdef HAVE_MYSQL
-+  db_mysql_dlopen();
-+
-+  MYSQL *db = f.mysql_init_fn(0);
-+  char *host, *user, *pass, *database, *unix_socket;
-+  unsigned int port;
-+  char *db_url = malloc(strlen(file)+1);
-+  char *create_database_statement;
-+
-+  if (db_url == NULL)
-+    csync_fatal("No memory for db_url\n");
-+
-+  strcpy(db_url, file);
-+  int rc = db_mysql_parse_url(db_url, &host, &user, &pass, &database, &port, &unix_socket);
-+  if (rc != DB_OK) {
-+    return rc;
-+  }
-+
-+  if (f.mysql_real_connect_fn(db, host, user, pass, database, port, unix_socket, 0) == NULL) {
-+    if (f.mysql_errno_fn(db) == ER_BAD_DB_ERROR) {
-+      if (f.mysql_real_connect_fn(db, host, user, pass, NULL, port, unix_socket, 0) != NULL) {
-+	ASPRINTF(&create_database_statement, "create database %s", database);
-+
-+	csync_debug(2, "creating database %s\n", database);
-+        if (f.mysql_query_fn(db, create_database_statement) != 0)
-+          csync_fatal("Cannot create database %s: Error: %s\n", database, f.mysql_error_fn(db));
-+	free(create_database_statement);
-+
-+	f.mysql_close_fn(db);
-+	db = f.mysql_init_fn(0);
-+
-+        if (f.mysql_real_connect_fn(db, host, user, pass, database, port, unix_socket, 0) == NULL)
-+          goto fatal;
-+      }
-+    } else
-+fatal:
-+      csync_fatal("Failed to connect to database: Error: %s\n", f.mysql_error_fn(db));
-+  }
-+
-+  db_conn_p conn = calloc(1, sizeof(*conn));
-+  if (conn == NULL) {
-+    return DB_ERROR;
-+  }
-+  *conn_p = conn;
-+  conn->private = db;
-+  conn->close = db_mysql_close;
-+  conn->exec = db_mysql_exec;
-+  conn->prepare = db_mysql_prepare;
-+  conn->errmsg = db_mysql_errmsg;
-+  conn->upgrade_to_schema = db_mysql_upgrade_to_schema;
-+
-+  return rc;
-+#else
-+  return DB_ERROR;
-+#endif
-+}
-+
-+#ifdef HAVE_MYSQL
-+
-+void db_mysql_close(db_conn_p conn)
-+{
-+  if (!conn)
-+    return;
-+  if (!conn->private) 
-+    return;
-+  f.mysql_close_fn(conn->private);
-+  conn->private = 0;
-+}
-+
-+const char *db_mysql_errmsg(db_conn_p conn)
-+{
-+  if (!conn)
-+    return "(no connection)";
-+  if (!conn->private)
-+    return "(no private data in conn)";
-+  return f.mysql_error_fn(conn->private);
-+}
-+
-+static void print_warnings(int level, MYSQL *m)
-+{
-+  int rc;
-+  MYSQL_RES *res;
-+  int fields;
-+  MYSQL_ROW row;
-+
-+  if (m == NULL)
-+    csync_fatal("print_warnings: m is NULL");
-+
-+  rc = f.mysql_query_fn(m, "SHOW WARNINGS");
-+  if (rc != 0)
-+    csync_fatal("print_warnings: Failed to get warning messages");
-+
-+  res = f.mysql_store_result_fn(m);
-+  if (res == NULL)
-+    csync_fatal("print_warnings: Failed to get result set for warning messages");
-+
-+  fields = f.mysql_num_fields_fn(res);
-+  if (fields < 2)
-+    csync_fatal("print_warnings: Strange: show warnings result set has less than 2 rows");
-+
-+  row = f.mysql_fetch_row_fn(res);
-+
-+  while (row) {
-+    csync_debug(level, "MySql Warning: %s\n", row[2]);
-+    row = f.mysql_fetch_row_fn(res);
-+  }
-+
-+  f.mysql_free_result_fn(res);
-+}
-+
-+int db_mysql_exec(db_conn_p conn, const char *sql) 
-+{
-+  int rc = DB_ERROR;
-+  if (!conn)
-+    return DB_NO_CONNECTION; 
-+
-+  if (!conn->private) {
-+    /* added error element */
-+    return DB_NO_CONNECTION_REAL;
-+  }
-+  rc = f.mysql_query_fn(conn->private, sql);
-+
-+/* Treat warnings as errors. For example when a column is too short this should
-+   be an error. */
-+
-+  if (f.mysql_warning_count_fn(conn->private) > 0) {
-+    print_warnings(1, conn->private);
-+    return DB_ERROR;
-+  }
-+
-+  /* On error parse, create DB ERROR element */
-+  return rc;
-+}
-+
-+int db_mysql_prepare(db_conn_p conn, const char *sql, db_stmt_p *stmt_p, 
-+		     char **pptail) {
-+  int rc = DB_ERROR;
-+
-+  *stmt_p = NULL;
-+
-+  if (!conn)
-+    return DB_NO_CONNECTION;
-+
-+  if (!conn->private) {
-+    /* added error element */
-+    return DB_NO_CONNECTION_REAL;
-+  }
-+  db_stmt_p stmt = malloc(sizeof(*stmt));
-+  /* TODO avoid strlen, use configurable limit? */
-+  rc = f.mysql_query_fn(conn->private, sql);
-+
-+/* Treat warnings as errors. For example when a column is too short this should
-+   be an error. */
-+
-+  if (f.mysql_warning_count_fn(conn->private) > 0) {
-+    print_warnings(1, conn->private);
-+    return DB_ERROR;
-+  }
-+
-+  MYSQL_RES *mysql_stmt = f.mysql_store_result_fn(conn->private);
-+  if (mysql_stmt == NULL) {
-+    csync_debug(2, "Error in mysql_store_result: %s", f.mysql_error_fn(conn->private));
-+    return DB_ERROR;
-+  }
-+
-+/* Treat warnings as errors. For example when a column is too short this should
-+   be an error. */
-+
-+  if (f.mysql_warning_count_fn(conn->private) > 0) {
-+    print_warnings(1, conn->private);
-+    return DB_ERROR;
-+  }
-+
-+  stmt->private = mysql_stmt;
-+  /* TODO error mapping / handling */
-+  *stmt_p = stmt;
-+  stmt->get_column_text = db_mysql_stmt_get_column_text;
-+  stmt->get_column_blob = db_mysql_stmt_get_column_blob;
-+  stmt->get_column_int = db_mysql_stmt_get_column_int;
-+  stmt->next = db_mysql_stmt_next;
-+  stmt->close = db_mysql_stmt_close;
-+  stmt->db = conn;
-+  return DB_OK;
-+}
-+
-+const void* db_mysql_stmt_get_column_blob(db_stmt_p stmt, int column) {
-+  if (!stmt || !stmt->private2) {
-+    return 0;
-+  }
-+  MYSQL_ROW row = stmt->private2;
-+  return row[column];
-+}
-+
-+const char *db_mysql_stmt_get_column_text(db_stmt_p stmt, int column) {
-+  if (!stmt || !stmt->private2) {
-+    return 0;
-+  }
-+  MYSQL_ROW row = stmt->private2;
-+  return row[column];
-+}
-+
-+int db_mysql_stmt_get_column_int(db_stmt_p stmt, int column) {
-+  const char *value = db_mysql_stmt_get_column_text(stmt, column);
-+  if (value)
-+    return atoi(value);
-+  /* error mapping */
-+  return 0;
-+}
-+
-+
-+int db_mysql_stmt_next(db_stmt_p stmt)
-+{
-+  MYSQL_RES *mysql_stmt = stmt->private;
-+  stmt->private2 = f.mysql_fetch_row_fn(mysql_stmt);
-+  /* error mapping */ 
-+  if (stmt->private2)
-+    return DB_ROW;
-+  return DB_DONE;
-+}
-+
-+int db_mysql_stmt_close(db_stmt_p stmt)
-+{
-+  MYSQL_RES *mysql_stmt = stmt->private;
-+  f.mysql_free_result_fn(mysql_stmt);
-+  free(stmt);
-+  return DB_OK; 
-+}
-+
-+
-+int db_mysql_upgrade_to_schema(int version)
-+{
-+	if (version < 0)
-+		return DB_OK;
-+
-+	if (version > 0)
-+		return DB_ERROR;
-+
-+	csync_debug(2, "Upgrading database schema to version %d.\n", version);
-+
-+/* We want proper logging, so use the csync sql function instead
-+ * of that from the database layer.
-+ */
-+	csync_db_sql("Creating action table",
-+		"CREATE TABLE `action` ("
-+		"  `filename` varchar(4096) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,"
-+		"  `command` text,"
-+		"  `logfile` text,"
-+		"  UNIQUE KEY `filename` (`filename`(326),`command`(20))"
-+		")");
-+
-+	csync_db_sql("Creating dirty table",
-+		"CREATE TABLE `dirty` ("
-+		"  `filename` varchar(4096) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,"
-+		"  `forced`   int(11)      DEFAULT NULL,"
-+		"  `myname`   varchar(50)  DEFAULT NULL,"
-+		"  `peername` varchar(50)  DEFAULT NULL,"
-+		"  UNIQUE KEY `filename` (`filename`(316),`peername`),"
-+		"  KEY `dirty_host` (`peername`(10))"
-+		")");
-+
-+	csync_db_sql("Creating file table",
-+		"CREATE TABLE `file` ("
-+		"  `filename` varchar(4096) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,"
-+		"  `checktxt` varchar(200) DEFAULT NULL,"
-+		"  UNIQUE KEY `filename` (`filename`(333))"
-+		")");
-+
-+	csync_db_sql("Creating hint table",
-+		"CREATE TABLE `hint` ("
-+		"  `filename` varchar(4096) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,"
-+		"  `recursive` int(11)     DEFAULT NULL"
-+		")");
-+
-+	csync_db_sql("Creating x509_cert table",
-+		"CREATE TABLE `x509_cert` ("
-+		"  `peername` varchar(50)  DEFAULT NULL,"
-+		"  `certdata` varchar(255) DEFAULT NULL,"
-+		"  UNIQUE KEY `peername` (`peername`)"
-+		")");
-+
-+/* csync_db_sql does a csync_fatal on error, so we always return DB_OK here. */
-+
-+	return DB_OK;
-+}
-+
-+
-+#endif
-diff --git a/db_mysql.h b/db_mysql.h
-new file mode 100644
-index 0000000..c5aeab3
---- /dev/null
-+++ b/db_mysql.h
-@@ -0,0 +1,19 @@
-+
-+#ifndef DB_MYSQL_H
-+#define DB_MYSQL_H
-+
-+/* public */
-+int   db_mysql_open(const char *file, db_conn_p *conn_p);
-+/* Private */
-+void  db_mysql_close(db_conn_p db_conn);
-+int   db_mysql_exec(db_conn_p conn, const char *sql);
-+int   db_mysql_prepare(db_conn_p conn, const char *sql, db_stmt_p *stmt_p, char **pptail);
-+int   db_mysql_stmt_next(db_stmt_p stmt);
-+const void* db_mysql_stmt_get_column_blob(db_stmt_p stmt, int column);
-+const char *db_mysql_stmt_get_column_text(db_stmt_p stmt, int column);
-+int   db_mysql_stmt_get_column_int(db_stmt_p stmt, int column);
-+int   db_mysql_stmt_close(db_stmt_p stmt);
-+const char *db_mysql_errmsg(db_conn_p db_conn);
-+int   db_mysql_upgrade_to_schema(int version);
-+
-+#endif
-diff --git a/db_postgres.c b/db_postgres.c
-new file mode 100644
-index 0000000..b40bdfb
---- /dev/null
-+++ b/db_postgres.c
-@@ -0,0 +1,458 @@
-+/*
-+ *  Copyright (C) 2010  Dennis Schafroth <dennis@schafroth.com>
-+ *  Copyright (C) 2010  Johannes Thoma <johannes.thoma@gmx.at>
-+ *
-+ *  This program is free software; you can redistribute it and/or modify
-+ *  it under the terms of the GNU General Public License as published by
-+ *  the Free Software Foundation; either version 2 of the License, or
-+ *  (at your option) any later version.
-+ *
-+ *  This program 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 General Public License for more details.
-+ *
-+ *  You should have received a copy of the GNU General Public License
-+ *  along with this program; if not, write to the Free Software
-+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
-+ */
-+
-+#include "csync2.h"
-+#include <stdio.h>
-+#include <stdarg.h>
-+#include <stdlib.h>
-+#include <unistd.h>
-+#include <signal.h>
-+#include <time.h>
-+#include <string.h>
-+#include "db_api.h"
-+#include "db_postgres.h"
-+#include "dl.h"
-+
-+#ifdef HAVE_POSTGRES
-+#include <postgresql/libpq-fe.h>
-+#endif
-+
-+#if (!defined HAVE_POSTGRES)
-+int db_postgres_open(const char *file, db_conn_p *conn_p)
-+{
-+	return DB_ERROR;
-+}
-+#else
-+
-+static struct db_postgres_fns {
-+        PGconn *(*PQconnectdb_fn)(char *);
-+        ConnStatusType (*PQstatus_fn)(const PGconn *);
-+        char *(*PQerrorMessage_fn)(const PGconn *);
-+	void (*PQfinish_fn)(PGconn *);
-+	PGresult *(*PQexec_fn)(PGconn *, const char *);
-+	ExecStatusType (*PQresultStatus_fn)(const PGresult *);
-+	char *(*PQresultErrorMessage_fn)(const PGresult *);
-+	void (*PQclear_fn)(PGresult *);
-+	int (*PQntuples_fn)(const PGresult *);
-+	char *(*PQgetvalue_fn)(const PGresult *, int, int);
-+} f;
-+
-+static void *dl_handle;
-+
-+
-+static void db_postgres_dlopen(void)
-+{
-+	csync_debug(1, "Opening shared library libpq.so\n");
-+
-+        dl_handle = dlopen("libpq.so", RTLD_LAZY);
-+        if (dl_handle == NULL) {
-+                csync_fatal("Could not open libpq.so: %s\nPlease install postgres client library (libpg) or use other database (sqlite, mysql)\n", dlerror());
-+        }
-+	csync_debug(1, "Reading symbols from shared library libpq.so\n");
-+
-+        LOOKUP_SYMBOL(dl_handle, PQconnectdb);
-+        LOOKUP_SYMBOL(dl_handle, PQstatus);
-+        LOOKUP_SYMBOL(dl_handle, PQerrorMessage);
-+        LOOKUP_SYMBOL(dl_handle, PQfinish);
-+        LOOKUP_SYMBOL(dl_handle, PQexec);
-+        LOOKUP_SYMBOL(dl_handle, PQresultStatus);
-+        LOOKUP_SYMBOL(dl_handle, PQresultErrorMessage);
-+        LOOKUP_SYMBOL(dl_handle, PQclear);
-+        LOOKUP_SYMBOL(dl_handle, PQntuples);
-+        LOOKUP_SYMBOL(dl_handle, PQgetvalue);
-+}
-+
-+
-+
-+/* Thi function parses a URL string like pgsql://[user[:passwd]@]hostname[:port]/database.
-+   and returns the result in the given parameters.
-+
-+   If an optional keyword is not given, the value of the parameter is not changed.
-+*/
-+
-+static int db_pgsql_parse_url(char *url, char **host, char **user, char **pass, char **database, unsigned int *port) 
-+{
-+  char *pos = strchr(url, '@'); 
-+  if (pos) {
-+    *(pos) = 0;
-+    *(user) = url;
-+    url = pos + 1;
-+
-+    pos = strchr(*user, ':');
-+    if (pos) {
-+      *(pos) = 0;
-+      *(pass) = (pos +1);
-+    }
-+  }
-+  *host = url;
-+  pos = strchr(*host, '/');
-+  if (pos) {
-+    // Database
-+    (*pos) = 0;
-+    *database = pos+1;
-+  }
-+  pos = strchr(*host, ':');
-+  if (pos) {
-+    (*pos) = 0;
-+    *port = atoi(pos+1);
-+  }
-+  return DB_OK;
-+}
-+
-+int db_postgres_open(const char *file, db_conn_p *conn_p)
-+{
-+  PGconn *pg_conn;
-+  char *host, *user, *pass, *database;
-+  unsigned int port = 5432;  /* default postgres port */
-+  char *db_url = malloc(strlen(file)+1);
-+  char *create_database_statement;
-+  char *pg_conn_info;
-+
-+  db_postgres_dlopen();
-+
-+  if (db_url == NULL)
-+    csync_fatal("No memory for db_url\n");
-+
-+  user = "postgres";
-+  pass = "";
-+  host = "localhost";
-+  database = "csync2";
-+
-+  strcpy(db_url, file);
-+  int rc = db_pgsql_parse_url(db_url, &host, &user, &pass, &database, &port);
-+  if (rc != DB_OK)
-+    return rc;
-+
-+  ASPRINTF(&pg_conn_info, "host='%s' user='%s' password='%s' dbname='%s' port=%d",
-+	host, user, pass, database, port);
-+
-+  pg_conn = f.PQconnectdb_fn(pg_conn_info);
-+  if (pg_conn == NULL)
-+    csync_fatal("No memory for postgress connection handle\n");
-+
-+  if (f.PQstatus_fn(pg_conn) != CONNECTION_OK) {
-+    f.PQfinish_fn(pg_conn);