]> arthur.barton.de Git - netatalk.git/commitdiff
New MySQL CNID backend
authorRalph Boehme <sloowfranklin@gmail.com>
Sun, 13 Oct 2013 14:16:54 +0000 (16:16 +0200)
committerRalph Boehme <sloowfranklin@gmail.com>
Wed, 23 Oct 2013 08:53:24 +0000 (10:53 +0200)
o add configure check --with-mysql-config=PATH that searches for
  the mysql-config binary
o add new MySQL CNID subdirectory and compilation infrastructure
o modify CNID header files for new backend
o add private CNID MySQL header file for private data
o add mysql config options
o add MySQL args to cnid_open()
o add support for MySQL CNID backend to dbd

Add MySQL libraries as deps to executables:
workaround libtool bug where the rpath of a dependent library (ie mysql) of a libtool
library (ie libatalk) gets stripped from the link flags when linking the final
executable, even though the library (mysql) is a non default OS dir.

53 files changed:
NEWS
bin/ad/Makefile.am
bin/ad/ad_find.c
bin/ad/ad_util.c
bin/afppasswd/Makefile.am
bin/misc/Makefile.am
bin/uniconv/Makefile.am
bin/uniconv/uniconv.c
configure.ac
etc/afpd/Makefile.am
etc/afpd/afp_options.c
etc/afpd/catsearch.c
etc/afpd/file.c
etc/afpd/volume.c
etc/cnid_dbd/Makefile.am
etc/cnid_dbd/cmd_dbd.c
etc/cnid_dbd/cnid_metad.c
etc/cnid_dbd/comm.c
etc/cnid_dbd/comm.h
etc/cnid_dbd/dbd.h
etc/cnid_dbd/dbd_add.c
etc/cnid_dbd/dbd_dbcheck.c
etc/cnid_dbd/dbd_delete.c
etc/cnid_dbd/dbd_get.c
etc/cnid_dbd/dbd_getstamp.c
etc/cnid_dbd/dbd_lookup.c
etc/cnid_dbd/dbd_rebuild_add.c
etc/cnid_dbd/dbd_resolve.c
etc/cnid_dbd/dbd_search.c
etc/cnid_dbd/dbd_update.c
etc/cnid_dbd/main.c
etc/cnid_dbd/pack.c
etc/cnid_dbd/pack.h
etc/cnid_dbd/usockfd.h
etc/netatalk/Makefile.am
etc/spotlight/Makefile.am
include/atalk/Makefile.am
include/atalk/cnid.h
include/atalk/cnid_bdb_private.h [new file with mode: 0644]
include/atalk/cnid_dbd_private.h [deleted file]
include/atalk/cnid_mysql_private.h [new file with mode: 0644]
include/atalk/globals.h
libatalk/Makefile.am
libatalk/cnid/Makefile.am
libatalk/cnid/cnid.c
libatalk/cnid/cnid_init.c
libatalk/cnid/dbd/cnid_dbd.c
libatalk/cnid/mysql/Makefile.am [new file with mode: 0644]
libatalk/cnid/mysql/cnid_mysql.c [new file with mode: 0644]
libatalk/util/netatalk_conf.c
macros/cnid-backend.m4
macros/summary.m4
test/afpd/Makefile.am

diff --git a/NEWS b/NEWS
index 504d2c0814ebacca7784ba6d8587db903ccc2585..0a4b5d9c46b39d421f13d8033ef450e236bc3944 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,7 @@ Changes in 3.1.0
        result of autodetecting dbus-glib presence
 * NEW: Add recvfile support with splice() on Linux. New global options
        "recvfile" (default: no) and "splice size" (default 64k).
+* NEW: CNID backend "mysql" for use with a MySQL server
 
 Changes in 3.0.6
 ================
index 5c3f47b67f918c634dc9247d97d3c70e42896f5c..e7b2c147f53ff8bc738b61f912344335278c3974 100644 (file)
@@ -18,8 +18,7 @@ ad_SOURCES = \
 ad_CFLAGS = -D_PATH_AD=\"$(bindir)/ad\"
 
 ad_LDADD = \
-       $(top_builddir)/libatalk/cnid/libcnid.la \
        $(top_builddir)/libatalk/libatalk.la \
-       @ACL_LIBS@
+       @ACL_LIBS@ @MYSQL_LIBS@
 
 endif
index 88a46752e2f1199b20f506c3a9d0034c912e645b..093414a1d5e104f5e224c3697dac1e7ef01a9ce8 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <atalk/adouble.h>
 #include <atalk/cnid.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/bstrlib.h>
 #include <atalk/bstradd.h>
 #include <atalk/directory.h>
index 7d4d2fb9e832fbb009fccb9a5b17588a73360076..782bbffa6c7a0042f7f97c6c02e732e67ef32ea9 100644 (file)
@@ -129,7 +129,8 @@ int openvol(AFPObj *obj, const char *path, afpvol_t *vol)
                                      "dbd",
                                      flags,
                                      vol->vol->v_cnidserver,
-                                     vol->vol->v_cnidport)) == NULL)
+                                     vol->vol->v_cnidport,
+                                     NULL, NULL)) == NULL)
         ERROR("Cant initialize CNID database connection for %s", vol->vol->v_path);
 
     cnid_getstamp(vol->vol->v_cdb,
index cab2df66125687dc2014435fd59fac1cd28fea43..578eac1b0a0970a85be4a12175afb65bf7fc35ae 100644 (file)
@@ -9,7 +9,7 @@ bin_PROGRAMS =
 endif
 
 afppasswd_SOURCES = afppasswd.c
-afppasswd_LDADD = $(top_builddir)/libatalk/libatalk.la @SSL_LIBS@
+afppasswd_LDADD = $(top_builddir)/libatalk/libatalk.la @SSL_LIBS@ @MYSQL_LIBS@
 
 AM_CFLAGS = @SSL_CFLAGS@ -I$(top_srcdir)/sys \
     -D_PATH_AFPDPWFILE=\"$(pkgconfdir)/afppasswd\"
index 5b2fd4e3ffc3154547b344dfaf152710a76f60e0..2cbb8d0a33acb37e625f9a1802c0de7fb2d72add 100644 (file)
@@ -6,18 +6,18 @@ bin_PROGRAMS =
 noinst_PROGRAMS = netacnv logger_test fce
 
 netacnv_SOURCES = netacnv.c
-netacnv_LDADD = $(top_builddir)/libatalk/libatalk.la
+netacnv_LDADD = $(top_builddir)/libatalk/libatalk.la @MYSQL_LIBS@
 
 logger_test_SOURCES = logger_test.c
-logger_test_LDADD = $(top_builddir)/libatalk/libatalk.la
+logger_test_LDADD = $(top_builddir)/libatalk/libatalk.la @MYSQL_LIBS@
 
 fce_SOOURCE = fce.c
-fce_LDADD = $(top_builddir)/libatalk/libatalk.la
+fce_LDADD = $(top_builddir)/libatalk/libatalk.la @MYSQL_LIBS@
 fce_CFLAGS = -I$(top_srcdir)/include
 
 bin_PROGRAMS += afpldaptest
 afpldaptest_SOURCES = uuidtest.c
 afpldaptest_CFLAGS = -D_PATH_CONFDIR=\"$(pkgconfdir)/\" @LDAP_CFLAGS@
 afpldaptest_LDFLAGS = @LDAP_LDFLAGS@
-afpldaptest_LDADD  = $(top_builddir)/libatalk/libatalk.la
+afpldaptest_LDADD  = $(top_builddir)/libatalk/libatalk.la @MYSQL_LIBS@
 
index 202e7227cfb9a8da2e2ce56253c4efd52afdfde2..58bbd0bee419f85dbe3fba634179f89e94be6562 100644 (file)
@@ -5,4 +5,4 @@ INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/sys
 bin_PROGRAMS = uniconv
 
 uniconv_SOURCES = uniconv.c iso8859_1_adapted.c
-uniconv_LDADD = $(top_builddir)/libatalk/cnid/libcnid.la $(top_builddir)/libatalk/libatalk.la
+uniconv_LDADD = $(top_builddir)/libatalk/libatalk.la @MYSQL_LIBS@
index 8a786a601dd4c1c641bc8c3d4c2bb8730e67eea6..93439cefa965efae35bab8255d0c97d7d1f04780 100644 (file)
@@ -389,7 +389,7 @@ static int init(char* path)
 {
        DIR* startdir;
 
-    if (NULL == (cdb = cnid_open (path, 0, cnid_type, 0, "localhost", "4700")) ) {
+    if (NULL == (cdb = cnid_open (path, 0, cnid_type, 0, "localhost", "4700", NULL, NULL)) ) {
                 fprintf (stderr, "ERROR: cannot open CNID database in '%s'\n", path);
                 fprintf (stderr, "ERROR: check the logs for reasons, aborting\n");
                return -1;
index b3dba04365e976a00745791d43f00b47b8d68761..8902ae1e8da15c350c7adaca4064fa5c5dd44e4a 100644 (file)
@@ -285,6 +285,7 @@ AC_OUTPUT([Makefile
        libatalk/cnid/last/Makefile
        libatalk/cnid/dbd/Makefile
        libatalk/cnid/tdb/Makefile
+       libatalk/cnid/mysql/Makefile
        libatalk/compat/Makefile
        libatalk/dsi/Makefile
        libatalk/iniparser/Makefile
index 8cfe75a4f94efbdfb3c1055067f7dc8daf330643..a0b210e170e05a4e2029881c8a5a269760d573cd 100644 (file)
@@ -51,7 +51,7 @@ afpd_SOURCES = \
 
 afpd_LDADD =  \
        $(top_builddir)/libatalk/libatalk.la \
-       @LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@
+       @LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@ @MYSQL_LIBS@
 
 afpd_LDFLAGS = -export-dynamic
 
index 932e6a657ea5215faa3ca69f7ec371425d62f2ef..f06bfb373665ca9bc4ff25c8be20501ceb04619e 100644 (file)
@@ -93,6 +93,9 @@ static void show_version( void )
 #endif
 #ifdef CNID_BACKEND_TDB
        printf( "tdb " );
+#endif
+#ifdef CNID_BACKEND_MYSQL
+       printf( "mysql " );
 #endif
        puts( "" );
 }
index 63a9607cdc130acd32faba44906678cfdfc3510e..bec7b15245b195e1311fde72d72eba838108a9d2 100644 (file)
@@ -46,7 +46,7 @@
 #include <atalk/adouble.h>
 #include <atalk/logger.h>
 #include <atalk/cnid.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/util.h>
 #include <atalk/bstradd.h>
 #include <atalk/unicode.h>
index edb55ea3eafced56c9464077a45360266f444779..cb8a968af09ddf491721b18b6b691f0fa97b62ce 100644 (file)
@@ -252,7 +252,7 @@ restart:
                     }
                     LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
                         vol->v_path);
-                    vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL);
+                    vol->v_cdb = cnid_open(vol->v_path, vol->v_umask, "tdb", flags, NULL, NULL, NULL, NULL);
                     if (vol->v_cdb) {
                         if (!(vol->v_flags & AFPVOL_TM)) {
                             vol->v_flags |= AFPVOL_RO;
index 4efa659f02ee02eccb4f4f4fe53216ca606e5852..07cfb42b293f199e9c2eeec4a74975c0a500aeda 100644 (file)
@@ -646,7 +646,9 @@ static int volume_openDB(const AFPObj *obj, struct vol *volume)
                               volume->v_cnidscheme,
                               flags,
                               volume->v_cnidserver,
-                              volume->v_cnidport);
+                              volume->v_cnidport,
+                              (const void *)obj,
+                              volume->v_uuid);
 
     if ( ! volume->v_cdb && ! (flags & CNID_FLAG_MEMORY)) {
         /* The first attempt failed and it wasn't yet an attempt to open in-memory */
@@ -655,7 +657,7 @@ static int volume_openDB(const AFPObj *obj, struct vol *volume)
         LOG(log_error, logtype_afpd, "Reopen volume %s using in memory temporary CNID DB.",
             volume->v_path);
         flags |= CNID_FLAG_MEMORY;
-        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL);
+        volume->v_cdb = cnid_open (volume->v_path, volume->v_umask, "tdb", flags, NULL, NULL, NULL, NULL);
 #ifdef SERVERTEXT
         /* kill ourself with SIGUSR2 aka msg pending */
         if (volume->v_cdb) {
index 3ebcbebb465d858df205e0acdbad2f68a2173e8d..a9133d9c7f45d3de60f046b362c19ab6939dc947 100644 (file)
@@ -11,10 +11,10 @@ cnid_dbd_SOURCES = dbif.c pack.c comm.c db_param.c main.c \
                    dbd_add.c dbd_get.c dbd_resolve.c dbd_lookup.c \
                    dbd_update.c dbd_delete.c dbd_getstamp.c \
                    dbd_rebuild_add.c dbd_dbcheck.c dbd_search.c
-cnid_dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@ @ACL_LIBS@
+cnid_dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@ @ACL_LIBS@ @MYSQL_LIBS@
 
 cnid_metad_SOURCES = cnid_metad.c usockfd.c db_param.c
-cnid_metad_LDADD = $(top_builddir)/libatalk/libatalk.la @ACL_LIBS@
+cnid_metad_LDADD = $(top_builddir)/libatalk/libatalk.la @ACL_LIBS@ @MYSQL_LIBS@
 
 dbd_SOURCES = cmd_dbd.c \
        cmd_dbd_scanvol.c \
@@ -26,7 +26,7 @@ dbd_SOURCES = cmd_dbd.c \
        dbd_rebuild_add.c \
        dbd_resolve.c \
        dbd_update.c
-dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@ @ACL_LIBS@
+dbd_LDADD = $(top_builddir)/libatalk/libatalk.la @BDB_LIBS@ @ACL_LIBS@ @MYSQL_LIBS@
 
 noinst_HEADERS = dbif.h pack.h db_param.h dbd.h usockfd.h comm.h cmd_dbd.h
 
index 31d74e6c8b06724e6e1e1102393fa66cd1d18a69..4018eecceb3e3814b030f7f94a5b0cbf883e07d3 100644 (file)
@@ -228,16 +228,18 @@ int main(int argc, char **argv)
     }
 
     /* open volume */
-    if (STRCMP(vol->v_cnidscheme, != , "dbd")) {
+    if (STRCMP(vol->v_cnidscheme, != , "dbd") && STRCMP(vol->v_cnidscheme, != , "mysql")) {
         dbd_log(LOGSTD, "\"%s\" isn't a \"dbd\" CNID volume", vol->v_path);
         exit(EXIT_FAILURE);
     }
     if ((vol->v_cdb = cnid_open(vol->v_path,
                                 0000,
-                                "dbd",
+                                vol->v_cnidscheme,
                                 vol->v_flags & AFPVOL_NODEV ? CNID_FLAG_NODEV : 0,
                                 vol->v_cnidserver,
-                                vol->v_cnidport)) == NULL) {
+                                vol->v_cnidport,
+                                &obj,
+                                vol->v_uuid)) == NULL) {
         dbd_log(LOGSTD, "Cant initialize CNID database connection for %s", vol->v_path);
         exit(EXIT_FAILURE);
     }
index 3d71094b328e4c2907eaf547c69bb4bf38a45f99..42b398f792c30707ad3c44db9d4e11353696256c 100644 (file)
@@ -87,7 +87,7 @@
 
 #include <atalk/util.h>
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/paths.h>
 #include <atalk/compat.h>
 #include <atalk/errchk.h>
index 7cd8f5598c7cff49930ac147f799e7dea1d210bb..28fab0e47b7a79d9b6315fc1e17e7063c0b09083 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <atalk/logger.h>
 #include <atalk/util.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/compat.h>
 
 #include "db_param.h"
index 46d91fc18fab1c8e97c815e91393ea73c418426e..2261777048a35887af881fc14698d72820337cff 100644 (file)
@@ -9,7 +9,7 @@
 /* number of seconds to try reading in readt */
 #define CNID_DBD_TIMEOUT 1
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 
 extern int      comm_init  (struct db_param *, int, int);
index 7b8da1cadab6fceb87952aa06613ec8848e74437..ab532d80438d68000913f545aa5de554e9eb38c1 100644 (file)
@@ -9,7 +9,7 @@
 
 #include <arpa/inet.h>
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 extern int add_cnid(DBD *dbd, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply);
 extern int get_cnid(DBD *dbd, struct cnid_dbd_rply *rply);
index db9c6cc29d23f5c3ba023032e97cd7e325b8ea54..3af72fa81aaab6f7515665bbf427e3cae03854e1 100644 (file)
@@ -15,7 +15,7 @@
 #include <sys/time.h>
 
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/cnid.h>
 #include <db.h>
 
index 98ce2210644a1c9df415789f8d82d334cd6ed3d1..27f9021eeffc45e8075183d96680c5332d145820 100644 (file)
@@ -15,7 +15,7 @@
 #include <arpa/inet.h>
 
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 #include "pack.h"
 #include "dbif.h"
index f34a9d500621ac9d967aab7200f111bc5d512bae..59109420c5f26342b39aa7495b05aaf20b556cde 100644 (file)
@@ -13,7 +13,7 @@
 #include <arpa/inet.h>
 
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 #include "dbif.h"
 #include "dbd.h"
index c1c7bb8cc44f28e100f1540f2ff110f29ec7f872..07d82da2b12698930aad8fc942ecb99189e68d02 100644 (file)
@@ -14,7 +14,7 @@
 #include <errno.h>
 #include <arpa/inet.h>
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 
 #include "dbif.h"
index ffba39721b620589d82b318baa3156070a7deeef..27270c76c1b66d2dcb010e77e95218d1b2443651 100644 (file)
@@ -14,7 +14,7 @@
 #include <errno.h>
 #include <arpa/inet.h>
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 #include "dbif.h"
 #include "dbd.h"
index f77b9fc2cb5f95a3abea20009fee1d980a7296ed..9ff4e411d356115829d7f3b6959168884d367047 100644 (file)
@@ -118,7 +118,7 @@ to be safe we must assign new CNIDs to both files.
 #include <arpa/inet.h>
 
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/cnid.h>
 
 #include "pack.h"
index f1bf7aca30fb219b4a9cb68d63c41c163d0e2a19..3aee1c9472da11a22cab8374d5312158b12bddf4 100644 (file)
@@ -13,7 +13,7 @@
 #include <arpa/inet.h>
 
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 #include "pack.h"
 #include "dbif.h"
index 53407757969b008256b7de3344250c53814f3d21..20ff8f7be1eb68694fa4efe60d1ef2bac590036b 100644 (file)
@@ -13,7 +13,7 @@
 #include <errno.h>
 #include <arpa/inet.h>
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 #include "dbif.h"
 #include "dbd.h"
index 66979424f868f8507c5ba0368d6c330067cb43a3..685eef67d594cbb2ef191f85c1fc2af9c454d404 100644 (file)
@@ -12,7 +12,7 @@
 #include <arpa/inet.h>
 
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 #include "dbif.h"
 #include "dbd.h"
index e8abf5d23dd3df7ee946b7ea8e362b2c62b4485e..7a95bfe720cb0fed4eb30d3095c1b12d59ba74db 100644 (file)
@@ -13,7 +13,7 @@
 #include <atalk/logger.h>
 #include <arpa/inet.h>
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 
 #include "pack.h"
index 0067504a0c6b3c4fd081e7eccbf1550272498a2b..97dcd5579a62735aeeed38a541c3ad39f54464c6 100644 (file)
@@ -22,7 +22,7 @@
 #include <sys/file.h>
 #include <arpa/inet.h>
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/logger.h>
 #include <atalk/errchk.h>
 #include <atalk/bstrlib.h>
index 2e9a32eec6a62234ad6cee93f084794d9accd620..dc61ddedede532df09531bf054d7f153c1c66251 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <atalk/unicode.h>
 #include <atalk/logger.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/volume.h>
 #include "pack.h"
 
index 9894d49a0a32a38aa27b2549227517b404af4d10..5566bea2520f921185fb3dcdccd24d2b92c4b00e 100644 (file)
@@ -8,7 +8,7 @@
 #define CNID_DBD_PACK_H 1
 
 #include <db.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 extern unsigned char *pack_cnid_data(struct cnid_dbd_rqst *);
 extern int didname(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey);
index 27bde63c31b6a6d665d87f264c85de059b53a96d..44f01ae2292d48775e47155341b7fd882413119c 100644 (file)
@@ -9,7 +9,7 @@
 
 
 
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 
 
 extern int      usockfd_create  (char *, mode_t, int);
index 6cf95eb6ccf7ed2b58cca9aac2d400f337914c27..ca3e163f68ce3d2c390cf8492325731aa7e94bcf 100644 (file)
@@ -12,6 +12,7 @@ netatalk_CFLAGS = \
        -D_PATH_CNID_METAD=\"$(sbindir)/cnid_metad\"
 
 netatalk_LDADD = \
+       @MYSQL_LIBS@ \
        $(top_builddir)/libatalk/libatalk.la
 
 netatalk_LDFLAGS =
index 7fd2721a4709f3de995e9766b9dc0b93d3978d63..60e0c25bead253f54e41eadd0fa6d475afa2e1f1 100644 (file)
@@ -34,5 +34,5 @@ srp_SOURCES = \
        spotlight_rawquery_lexer.l
 
 srp_CFLAGS = -DMAIN -I$(top_srcdir)/include @TRACKER_CFLAGS@
-srp_LDADD = $(top_builddir)/libatalk/libatalk.la
+srp_LDADD = $(top_builddir)/libatalk/libatalk.la @MYSQL_LIBS@
 endif
index 2f63e0f676e76edea239c6738f93c6751e3522e4..550741d6b473d7f7dd230343b165823ab6871485 100644 (file)
@@ -35,7 +35,8 @@ noinst_HEADERS = \
        server_child.h \
        server_ipc.h \
        tdb.h \
-       cnid_dbd_private.h \
+       cnid_bdb_private.h \
+       cnid_mysql_private.h \
        cnid_private.h \
        bstradd.h \
        errchk.h \
index ba0b62fad3d0d1e4149d5aeae63565e1b748e3f8..9c8e0bacd065a69afb363b499ee78024c41f26f3 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <atalk/adouble.h>
 #include <atalk/list.h>
+#include <atalk/uuid.h>
 
 /* CNID object flags */
 #define CNID_FLAG_PERSISTENT   0x01      /* This backend implements DID persistence */
@@ -81,8 +82,14 @@ struct cnid_open_args {
     const char *dir;
     mode_t mask;
     uint32_t flags;
-    const char *cnidserver;      /* for dbd */
-    const char *cnidport;        /* for dbd */
+
+    /* for dbd */
+    const char *cnidserver;
+    const char *cnidport;
+
+    /* for MySQL */
+    const void *obj;
+    char *voluuid;
 };
 
 /*
@@ -109,7 +116,9 @@ struct _cnid_db *cnid_open(const char *volpath,
                            char *type,
                            int flags,
                            const char *cnidsrv,
-                           const char *cnidport);
+                           const char *cnidport,
+                           const void *obj,
+                           char *uuid);
 cnid_t cnid_add        (struct _cnid_db *cdb, const struct stat *st, const cnid_t did,
                         const char *name, const size_t len, cnid_t hint);
 int    cnid_delete     (struct _cnid_db *cdb, cnid_t id);
diff --git a/include/atalk/cnid_bdb_private.h b/include/atalk/cnid_bdb_private.h
new file mode 100644 (file)
index 0000000..8aab3e0
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  Interface to the cnid_dbd daemon that stores/retrieves CNIDs from a database.
+ */
+
+
+#ifndef _ATALK_CNID_DBD_PRIVATE_H
+#define _ATALK_CNID_DBD_PRIVATE_H 1
+
+#include <sys/stat.h>
+#include <atalk/adouble.h>
+#include <sys/param.h>
+
+#include <atalk/cnid_private.h>
+
+#define CNID_DBD_OP_OPEN        0x01
+#define CNID_DBD_OP_CLOSE       0x02
+#define CNID_DBD_OP_ADD         0x03
+#define CNID_DBD_OP_GET         0x04
+#define CNID_DBD_OP_RESOLVE     0x05
+#define CNID_DBD_OP_LOOKUP      0x06
+#define CNID_DBD_OP_UPDATE      0x07
+#define CNID_DBD_OP_DELETE      0x08
+#define CNID_DBD_OP_MANGLE_ADD  0x09
+#define CNID_DBD_OP_MANGLE_GET  0x0a
+#define CNID_DBD_OP_GETSTAMP    0x0b
+#define CNID_DBD_OP_REBUILD_ADD 0x0c
+#define CNID_DBD_OP_SEARCH      0x0d
+#define CNID_DBD_OP_WIPE        0x0e
+
+#define CNID_DBD_RES_OK            0x00
+#define CNID_DBD_RES_NOTFOUND      0x01
+#define CNID_DBD_RES_ERR_DB        0x02
+#define CNID_DBD_RES_ERR_MAX       0x03
+#define CNID_DBD_RES_ERR_DUPLCNID  0x04
+#define CNID_DBD_RES_SRCH_CNT      0x05
+#define CNID_DBD_RES_SRCH_DONE     0x06
+
+#define DBD_MAX_SRCH_RSLTS 100
+
+struct cnid_dbd_rqst {
+    int     op;
+    cnid_t  cnid;
+    dev_t   dev;
+    ino_t   ino;
+    uint32_t type;
+    cnid_t  did;
+    const char *name;
+    size_t  namelen;
+};
+
+struct cnid_dbd_rply {
+    int     result;    
+    cnid_t  cnid;
+    cnid_t  did;
+    char    *name;
+    size_t  namelen;
+};
+
+typedef struct CNID_bdb_private {
+    uint32_t magic;
+    char      db_dir[MAXPATHLEN + 1]; /* Database directory without /.AppleDB appended */
+    char      *cnidserver;
+    char      *cnidport;
+    int       fd;              /* File descriptor to cnid_dbd */
+    char      stamp[ADEDLEN_PRIVSYN]; /* db timestamp */
+    char      *client_stamp;
+    size_t    stamp_size;
+    int       notfirst;   /* already open before */
+    int       changed;  /* stamp differ */
+} CNID_bdb_private;
+
+
+#endif /* include/atalk/cnid_dbd.h */
diff --git a/include/atalk/cnid_dbd_private.h b/include/atalk/cnid_dbd_private.h
deleted file mode 100644 (file)
index b61f7a8..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- *  Interface to the cnid_dbd daemon that stores/retrieves CNIDs from a database.
- */
-
-
-#ifndef _ATALK_CNID_DBD_PRIVATE_H
-#define _ATALK_CNID_DBD_PRIVATE_H 1
-
-#include <sys/stat.h>
-#include <atalk/adouble.h>
-#include <sys/param.h>
-
-#include <atalk/cnid_private.h>
-
-#define CNID_DBD_OP_OPEN        0x01
-#define CNID_DBD_OP_CLOSE       0x02
-#define CNID_DBD_OP_ADD         0x03
-#define CNID_DBD_OP_GET         0x04
-#define CNID_DBD_OP_RESOLVE     0x05
-#define CNID_DBD_OP_LOOKUP      0x06
-#define CNID_DBD_OP_UPDATE      0x07
-#define CNID_DBD_OP_DELETE      0x08
-#define CNID_DBD_OP_MANGLE_ADD  0x09
-#define CNID_DBD_OP_MANGLE_GET  0x0a
-#define CNID_DBD_OP_GETSTAMP    0x0b
-#define CNID_DBD_OP_REBUILD_ADD 0x0c
-#define CNID_DBD_OP_SEARCH      0x0d
-#define CNID_DBD_OP_WIPE        0x0e
-
-#define CNID_DBD_RES_OK            0x00
-#define CNID_DBD_RES_NOTFOUND      0x01
-#define CNID_DBD_RES_ERR_DB        0x02
-#define CNID_DBD_RES_ERR_MAX       0x03
-#define CNID_DBD_RES_ERR_DUPLCNID  0x04
-#define CNID_DBD_RES_SRCH_CNT      0x05
-#define CNID_DBD_RES_SRCH_DONE     0x06
-
-#define DBD_MAX_SRCH_RSLTS 100
-
-struct cnid_dbd_rqst {
-    int     op;
-    cnid_t  cnid;
-    dev_t   dev;
-    ino_t   ino;
-    uint32_t type;
-    cnid_t  did;
-    const char *name;
-    size_t  namelen;
-};
-
-struct cnid_dbd_rply {
-    int     result;    
-    cnid_t  cnid;
-    cnid_t  did;
-    char    *name;
-    size_t  namelen;
-};
-
-typedef struct CNID_private {
-    uint32_t magic;
-    char      db_dir[MAXPATHLEN + 1]; /* Database directory without /.AppleDB appended */
-    char      *cnidserver;
-    char      *cnidport;
-    int       fd;              /* File descriptor to cnid_dbd */
-    char      stamp[ADEDLEN_PRIVSYN]; /* db timestamp */
-    char      *client_stamp;
-    size_t    stamp_size;
-    int       notfirst;   /* already open before */
-    int       changed;  /* stamp differ */
-} CNID_private;
-
-
-#endif /* include/atalk/cnid_dbd.h */
diff --git a/include/atalk/cnid_mysql_private.h b/include/atalk/cnid_mysql_private.h
new file mode 100644 (file)
index 0000000..6affaf7
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef _ATALK_CNID_MYSQL_PRIVATE_H
+#define _ATALK_CNID_MYSQL_PRIVATE_H 1
+
+#include <atalk/cnid_private.h>
+#include <atalk/uuid.h>
+
+#define CNID_MYSQL_FLAG_DEPLETED (1 << 0) /* CNID set overflowed */
+
+typedef struct CNID_mysql_private {
+    uint32_t      cnid_mysql_flags;
+    uint32_t      cnid_mysql_magic;
+    char         *cnid_mysql_volname;
+    const void   *cnid_mysql_obj;
+    MYSQL        *cnid_mysql_con;
+    atalk_uuid_t  cnid_mysql_voluuid;
+    char         *cnid_mysql_voluuid_str;
+    cnid_t        cnid_mysql_hint;
+    MYSQL_STMT   *cnid_lookup_stmt;
+    MYSQL_STMT   *cnid_add_stmt;
+    MYSQL_STMT   *cnid_put_stmt;
+} CNID_mysql_private;
+
+#endif
index 8944ec8669d648041d2136d5193b814ae927bd9e..21b8b4e82ae842fb84282e9ef6bae10661f2b67e 100644 (file)
@@ -125,6 +125,10 @@ struct afp_options {
     char *ignored_attr;
     char *slmod_path;
     int  splice_size;
+    char *cnid_mysql_host;
+    char *cnid_mysql_user;
+    char *cnid_mysql_pw;
+    char *cnid_mysql_db;
     struct afp_volume_name volfile;
 };
 
index d8733b35e92d66f5f67e5415e0b64503bcb4268a..3220b89aac042229fc0c22881ce62870faebac67 100644 (file)
@@ -44,7 +44,7 @@ libatalk_la_CFLAGS = \
        @PTHREAD_CFLAGS@
 
 libatalk_la_LIBADD  = \
-       @WRAP_LIBS@ @ACL_LIBS@ @PTHREAD_LIBS@ \
+       @WRAP_LIBS@ @ACL_LIBS@ @PTHREAD_LIBS@ @MYSQL_LIBS@ \
        acl/libacl.la \
        adouble/libadouble.la   \
        bstring/libbstring.la \
index d1051e678783251d09452815fa7ad1fbce16b109..5c9dd52c93f1e7d5a7e6b7358bd2b61daaf04110 100644 (file)
@@ -17,6 +17,11 @@ if USE_TDB_BACKEND
 LIBCNID_DEPS += tdb/libcnid_tdb.la
 endif
 
+if USE_MYSQL_BACKEND
+SUBDIRS += mysql
+LIBCNID_DEPS += @MYSQL_LIBS@ mysql/libcnid_mysql.la
+endif
+
 libcnid_la_SOURCES = cnid.c cnid_init.c
 libcnid_la_LIBADD = $(LIBCNID_DEPS)
 
index 7cf3af1618d19a6de2e0cecada09936aeab90508..9212caccafa73ad1ef0c7585d4bdfa6a29782ed7 100644 (file)
@@ -92,7 +92,7 @@ static int cnid_dir(const char *dir, mode_t mask)
 
 /* Opens CNID database using particular back-end */
 struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int flags,
-                           const char *cnidsrv, const char *cnidport)
+                           const char *cnidsrv, const char *cnidport, const void *obj, char *uuid)
 {
     struct _cnid_db *db;
     cnid_module *mod = NULL;
@@ -128,7 +128,7 @@ struct _cnid_db *cnid_open(const char *volpath, mode_t mask, char *type, int fla
         }
     }
 
-    struct cnid_open_args args = {volpath, mask, flags, cnidsrv, cnidport};
+    struct cnid_open_args args = {volpath, mask, flags, cnidsrv, cnidport, obj, uuid};
     db = mod->cnid_open(&args);
 
     if ((mod->flags & CNID_FLAG_SETUID) && !(flags & CNID_FLAG_MEMORY)) {
index 75fc5db380f94f7a400a070b8eecde3c4abbdf52..03cad3886846359872ca50d2a543f2358a705e46 100644 (file)
@@ -56,6 +56,10 @@ extern struct _cnid_module cnid_dbd_module;
 extern struct _cnid_module cnid_tdb_module;
 #endif
 
+#ifdef CNID_BACKEND_MYSQL
+extern struct _cnid_module cnid_mysql_module;
+#endif
+
 void cnid_init(void)
 {
 #ifdef CNID_BACKEND_DB3
@@ -85,4 +89,8 @@ void cnid_init(void)
 #ifdef CNID_BACKEND_TDB
     cnid_register(&cnid_tdb_module);
 #endif
+
+#ifdef CNID_BACKEND_MYSQL
+    cnid_register(&cnid_mysql_module);
+#endif
 }
index 3f0278ae46aa9678e320e232580c52e53ea38535..1b365065cdd79194d2b8329fbef496bfa8ffdcf6 100644 (file)
@@ -31,7 +31,7 @@
 #include <atalk/logger.h>
 #include <atalk/adouble.h>
 #include <atalk/cnid.h>
-#include <atalk/cnid_dbd_private.h>
+#include <atalk/cnid_bdb_private.h>
 #include <atalk/util.h>
 
 #include "cnid_dbd.h"
@@ -224,7 +224,7 @@ static int write_vec(int fd, struct iovec *iov, ssize_t towrite, int vecs)
 }
 
 /* --------------------- */
-static int init_tsock(CNID_private *db)
+static int init_tsock(CNID_bdb_private *db)
 {
     int fd;
     int len;
@@ -256,7 +256,7 @@ static int init_tsock(CNID_private *db)
 }
 
 /* --------------------- */
-static int send_packet(CNID_private *db, struct cnid_dbd_rqst *rqst)
+static int send_packet(CNID_bdb_private *db, struct cnid_dbd_rqst *rqst)
 {
     struct iovec iov[2];
     size_t towrite;
@@ -312,7 +312,7 @@ static int dbd_reply_stamp(struct cnid_dbd_rply *rply)
  * assume send is non blocking
  * if no answer after sometime (at least MAX_DELAY secondes) return an error
  */
-static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+static int dbd_rpc(CNID_bdb_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
 {
     ssize_t ret;
     char *nametmp;
@@ -351,7 +351,7 @@ static int dbd_rpc(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd
 }
 
 /* -------------------- */
-static int transmit(CNID_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
+static int transmit(CNID_bdb_private *db, struct cnid_dbd_rqst *rqst, struct cnid_dbd_rply *rply)
 {
     time_t orig, t;
     int clean = 1; /* no errors so far - to prevent sleep on first try */
@@ -434,7 +434,7 @@ static struct _cnid_db *cnid_dbd_new(const char *volpath)
 /* ---------------------- */
 struct _cnid_db *cnid_dbd_open(struct cnid_open_args *args)
 {
-    CNID_private *db = NULL;
+    CNID_bdb_private *db = NULL;
     struct _cnid_db *cdb = NULL;
 
     if (!args->dir) {
@@ -446,7 +446,7 @@ struct _cnid_db *cnid_dbd_open(struct cnid_open_args *args)
         return NULL;
     }
 
-    if ((db = (CNID_private *)calloc(1, sizeof(CNID_private))) == NULL) {
+    if ((db = (CNID_bdb_private *)calloc(1, sizeof(CNID_bdb_private))) == NULL) {
         LOG(log_error, logtype_cnid, "cnid_open: Unable to allocate memory for database");
         goto cnid_dbd_open_fail;
     }
@@ -481,7 +481,7 @@ cnid_dbd_open_fail:
 /* ---------------------- */
 void cnid_dbd_close(struct _cnid_db *cdb)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
 
     if (!cdb) {
         LOG(log_error, logtype_cnid, "cnid_close called with NULL argument !");
@@ -505,7 +505,7 @@ void cnid_dbd_close(struct _cnid_db *cdb)
 /**
  * Get the db stamp
  **/
-static int cnid_dbd_stamp(CNID_private *db)
+static int cnid_dbd_stamp(CNID_bdb_private *db)
 {
     struct cnid_dbd_rqst rqst_stamp;
     struct cnid_dbd_rply rply_stamp;
@@ -532,7 +532,7 @@ static int cnid_dbd_stamp(CNID_private *db)
 cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
                     cnid_t did, const char *name, size_t len, cnid_t hint)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
     cnid_t id;
@@ -596,7 +596,7 @@ cnid_t cnid_dbd_add(struct _cnid_db *cdb, const struct stat *st,
 /* ---------------------- */
 cnid_t cnid_dbd_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
     cnid_t id;
@@ -649,7 +649,7 @@ cnid_t cnid_dbd_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t l
 /* ---------------------- */
 char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
     char *name;
@@ -708,7 +708,7 @@ char *cnid_dbd_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t le
  **/
 int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
 
     if (!cdb || !(db = cdb->_private) || len != ADEDLEN_PRIVSYN) {
         LOG(log_error, logtype_cnid, "cnid_getstamp: Parameter error");
@@ -725,7 +725,7 @@ int cnid_dbd_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
 cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
                        const char *name, size_t len)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
     cnid_t id;
@@ -786,7 +786,7 @@ cnid_t cnid_dbd_lookup(struct _cnid_db *cdb, const struct stat *st, cnid_t did,
 /* ---------------------- */
 int cnid_dbd_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
     int count;
@@ -842,7 +842,7 @@ int cnid_dbd_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *
 int cnid_dbd_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
                     cnid_t did, const char *name, size_t len)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
 
@@ -896,7 +896,7 @@ int cnid_dbd_update(struct _cnid_db *cdb, cnid_t id, const struct stat *st,
 cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
                             cnid_t did, const char *name, size_t len, cnid_t hint)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
     cnid_t id;
@@ -958,7 +958,7 @@ cnid_t cnid_dbd_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
 /* ---------------------- */
 int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
 
@@ -995,7 +995,7 @@ int cnid_dbd_delete(struct _cnid_db *cdb, const cnid_t id)
 
 int cnid_dbd_wipe(struct _cnid_db *cdb)
 {
-    CNID_private *db;
+    CNID_bdb_private *db;
     struct cnid_dbd_rqst rqst;
     struct cnid_dbd_rply rply;
 
diff --git a/libatalk/cnid/mysql/Makefile.am b/libatalk/cnid/mysql/Makefile.am
new file mode 100644 (file)
index 0000000..df688b2
--- /dev/null
@@ -0,0 +1,6 @@
+# Makefile.am for libatalk/cnid/mysql/
+
+noinst_LTLIBRARIES = libcnid_mysql.la
+libcnid_mysql_la_SOURCES = cnid_mysql.c
+libcnid_mysql_la_CFLAGS = @MYSQL_CFLAGS@
+libcnid_mysql_la_LIBADD = @MYSQL_LIBS@
diff --git a/libatalk/cnid/mysql/cnid_mysql.c b/libatalk/cnid/mysql/cnid_mysql.c
new file mode 100644 (file)
index 0000000..c661f9a
--- /dev/null
@@ -0,0 +1,961 @@
+/*
+ * Copyright (C) Ralph Boehme 2013
+ * All Rights Reserved.  See COPYING.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <net/if.h>
+#include <netinet/tcp.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <time.h>
+#include <arpa/inet.h>
+
+#include <mysql.h>
+#include <mysqld_error.h>
+#include <errmsg.h>
+
+#include <atalk/logger.h>
+#include <atalk/adouble.h>
+#include <atalk/util.h>
+#include <atalk/cnid_mysql_private.h>
+#include <atalk/cnid_bdb_private.h>
+#include <atalk/errchk.h>
+#include <atalk/globals.h>
+
+static MYSQL_BIND lookup_param[4], lookup_result[5];
+static MYSQL_BIND add_param[4], put_param[5];
+
+/*
+ * Prepared statement parameters
+ */
+static char               stmt_param_name[MAXPATHLEN];
+static unsigned long      stmt_param_name_len;
+static unsigned long long stmt_param_id;
+static unsigned long long stmt_param_did;
+static unsigned long long stmt_param_dev;
+static unsigned long long stmt_param_ino;
+
+/*
+ * lookup result parameters
+ */
+static unsigned long long lookup_result_id;
+static unsigned long long lookup_result_did;
+static char               lookup_result_name[MAXPATHLEN];
+static unsigned long      lookup_result_name_len;
+static unsigned long long lookup_result_dev;
+static unsigned long long lookup_result_ino;
+
+static int init_prepared_stmt_lookup(CNID_mysql_private *db)
+{
+    EC_INIT;
+    char *sql = NULL;
+
+    lookup_param[0].buffer_type    = MYSQL_TYPE_STRING;
+    lookup_param[0].buffer         = &stmt_param_name;
+    lookup_param[0].buffer_length  = sizeof(stmt_param_name);
+    lookup_param[0].length         = &stmt_param_name_len;
+
+    lookup_param[1].buffer_type    = MYSQL_TYPE_LONGLONG;
+    lookup_param[1].buffer         = &stmt_param_did;
+    lookup_param[1].is_unsigned    = true;
+
+    lookup_param[2].buffer_type    = MYSQL_TYPE_LONGLONG;
+    lookup_param[2].buffer         = &stmt_param_dev;
+    lookup_param[2].is_unsigned    = true;
+
+    lookup_param[3].buffer_type    = MYSQL_TYPE_LONGLONG;
+    lookup_param[3].buffer         = &stmt_param_ino;
+    lookup_param[3].is_unsigned    = true;
+
+    lookup_result[0].buffer_type   = MYSQL_TYPE_LONGLONG;
+    lookup_result[0].buffer        = &lookup_result_id;
+    lookup_result[0].is_unsigned   = true;
+
+    lookup_result[1].buffer_type   = MYSQL_TYPE_LONGLONG;
+    lookup_result[1].buffer        = &lookup_result_did;
+    lookup_result[1].is_unsigned   = true;
+
+    lookup_result[2].buffer_type   = MYSQL_TYPE_STRING;
+    lookup_result[2].buffer        = &lookup_result_name;
+    lookup_result[2].buffer_length = sizeof(lookup_result_name);
+    lookup_result[2].length        = &lookup_result_name_len;
+
+    lookup_result[3].buffer_type   = MYSQL_TYPE_LONGLONG;
+    lookup_result[3].buffer        = &lookup_result_dev;
+    lookup_result[3].is_unsigned   = true;
+
+    lookup_result[4].buffer_type   = MYSQL_TYPE_LONGLONG;
+    lookup_result[4].buffer        = &lookup_result_ino;
+    lookup_result[4].is_unsigned   = true;
+
+    EC_NULL( db->cnid_lookup_stmt = mysql_stmt_init(db->cnid_mysql_con) );
+    EC_NEG1( asprintf(&sql,
+                      "SELECT Id,Did,Name,DevNo,InodeNo FROM %s "
+                      "WHERE (Name=? AND Did=?) OR (DevNo=? AND InodeNo=?)",
+                      db->cnid_mysql_voluuid_str) );
+    EC_ZERO_LOG( mysql_stmt_prepare(db->cnid_lookup_stmt, sql, strlen(sql)) );
+    EC_ZERO_LOG( mysql_stmt_bind_param(db->cnid_lookup_stmt, lookup_param) );
+
+EC_CLEANUP:
+    if (sql)
+        free(sql);
+    EC_EXIT;
+}
+
+static int init_prepared_stmt_add(CNID_mysql_private *db)
+{
+    EC_INIT;
+    char *sql = NULL;
+
+    EC_NULL( db->cnid_add_stmt = mysql_stmt_init(db->cnid_mysql_con) );
+    EC_NEG1( asprintf(&sql,
+                      "INSERT INTO %s (Name,Did,DevNo,InodeNo) VALUES(?,?,?,?)",
+                      db->cnid_mysql_voluuid_str) );
+
+    add_param[0].buffer_type    = MYSQL_TYPE_STRING;
+    add_param[0].buffer         = &stmt_param_name;
+    add_param[0].buffer_length  = sizeof(stmt_param_name);
+    add_param[0].length         = &stmt_param_name_len;
+
+    add_param[1].buffer_type    = MYSQL_TYPE_LONGLONG;
+    add_param[1].buffer         = &stmt_param_did;
+    add_param[1].is_unsigned    = true;
+
+    add_param[2].buffer_type    = MYSQL_TYPE_LONGLONG;
+    add_param[2].buffer         = &stmt_param_dev;
+    add_param[2].is_unsigned    = true;
+
+    add_param[3].buffer_type    = MYSQL_TYPE_LONGLONG;
+    add_param[3].buffer         = &stmt_param_ino;
+    add_param[3].is_unsigned    = true;
+
+    EC_ZERO_LOG( mysql_stmt_prepare(db->cnid_add_stmt, sql, strlen(sql)) );
+    EC_ZERO_LOG( mysql_stmt_bind_param(db->cnid_add_stmt, add_param) );
+
+EC_CLEANUP:
+    if (sql)
+        free(sql);
+    EC_EXIT;
+}
+
+static int init_prepared_stmt_put(CNID_mysql_private *db)
+{
+    EC_INIT;
+    char *sql = NULL;
+
+    EC_NULL( db->cnid_put_stmt = mysql_stmt_init(db->cnid_mysql_con) );
+    EC_NEG1( asprintf(&sql,
+                      "INSERT INTO %s (Id,Name,Did,DevNo,InodeNo) VALUES(?,?,?,?,?)",
+                      db->cnid_mysql_voluuid_str) );
+
+    put_param[0].buffer_type    = MYSQL_TYPE_LONGLONG;
+    put_param[0].buffer         = &stmt_param_id;
+    put_param[0].is_unsigned    = true;
+
+    put_param[1].buffer_type    = MYSQL_TYPE_STRING;
+    put_param[1].buffer         = &stmt_param_name;
+    put_param[1].buffer_length  = sizeof(stmt_param_name);
+    put_param[1].length         = &stmt_param_name_len;
+
+    put_param[2].buffer_type    = MYSQL_TYPE_LONGLONG;
+    put_param[2].buffer         = &stmt_param_did;
+    put_param[2].is_unsigned    = true;
+
+    put_param[3].buffer_type    = MYSQL_TYPE_LONGLONG;
+    put_param[3].buffer         = &stmt_param_dev;
+    put_param[3].is_unsigned    = true;
+
+    put_param[4].buffer_type    = MYSQL_TYPE_LONGLONG;
+    put_param[4].buffer         = &stmt_param_ino;
+    put_param[4].is_unsigned    = true;
+
+    EC_ZERO_LOG( mysql_stmt_prepare(db->cnid_put_stmt, sql, strlen(sql)) );
+    EC_ZERO_LOG( mysql_stmt_bind_param(db->cnid_put_stmt, put_param) );
+
+EC_CLEANUP:
+    if (sql)
+        free(sql);
+    EC_EXIT;
+}
+
+static int init_prepared_stmt(CNID_mysql_private *db)
+{
+    EC_INIT;
+
+    EC_ZERO( init_prepared_stmt_lookup(db) );
+    EC_ZERO( init_prepared_stmt_add(db) );
+    EC_ZERO( init_prepared_stmt_put(db) );
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+
+static void close_prepared_stmt(CNID_mysql_private *db)
+{
+    mysql_stmt_close(db->cnid_lookup_stmt);
+    mysql_stmt_close(db->cnid_add_stmt);
+    mysql_stmt_close(db->cnid_put_stmt);
+}
+
+static int cnid_mysql_execute(MYSQL *con, char *fmt, ...)
+{
+    char *sql = NULL;
+    va_list ap;
+    int rv;
+
+    va_start(ap, fmt);
+    if (vasprintf(&sql, fmt, ap) == -1)
+        return -1;
+    va_end(ap);
+
+    LOG(log_maxdebug, logtype_cnid, "SQL: %s", sql);
+
+    rv = mysql_query(con, sql);
+
+    if (rv) {
+        LOG(log_info, logtype_cnid, "MySQL query \"%s\", error: %s", sql, mysql_error(con));
+        errno = CNID_ERR_DB;
+    }
+    free(sql);
+    return rv;
+}
+
+int cnid_mysql_delete(struct _cnid_db *cdb, const cnid_t id)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+
+    if (!cdb || !(db = cdb->_private) || !id) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_delete: Parameter error");
+        errno = CNID_ERR_PARAM;
+        EC_FAIL;
+    }
+
+    LOG(log_debug, logtype_cnid, "cnid_mysql_delete(%" PRIu32 "): BEGIN", ntohl(id));
+    
+    EC_NEG1( cnid_mysql_execute(db->cnid_mysql_con,
+                                "DELETE FROM %s WHERE Id=%" PRIu32,
+                                db->cnid_mysql_voluuid_str,
+                                ntohl(id)) );
+
+    LOG(log_debug, logtype_cnid, "cnid_mysql_delete(%" PRIu32 "): END", ntohl(id));
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+
+void cnid_mysql_close(struct _cnid_db *cdb)
+{
+    CNID_mysql_private *db;
+
+    if (!cdb) {
+        LOG(log_error, logtype_cnid, "cnid_close called with NULL argument !");
+        return;
+    }
+
+    if ((db = cdb->_private) != NULL) {
+        LOG(log_debug, logtype_cnid, "closing database connection for volume '%s'", db->cnid_mysql_volname);
+
+        free(db->cnid_mysql_voluuid_str);
+
+        close_prepared_stmt(db);
+
+        if (db->cnid_mysql_con)
+            mysql_close(db->cnid_mysql_con);
+        free(db);
+    }
+
+    free(cdb->volpath);
+    free(cdb);
+
+    return;
+}
+
+int cnid_mysql_update(struct _cnid_db *cdb,
+                      cnid_t id,
+                      const struct stat *st,
+                      cnid_t did,
+                      const char *name,
+                      size_t len)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+    cnid_t update_id;
+
+    if (!cdb || !(db = cdb->_private) || !id || !st || !name) {
+        LOG(log_error, logtype_cnid, "cnid_update: Parameter error");
+        errno = CNID_ERR_PARAM;
+        EC_FAIL;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_update: Path name is too long");
+        errno = CNID_ERR_PATH;
+        EC_FAIL;
+    }
+
+    uint64_t dev = st->st_dev;
+    uint64_t ino = st->st_ino;
+
+    do {
+        EC_NEG1( cnid_mysql_execute(db->cnid_mysql_con,
+                                    "DELETE FROM %s WHERE Id=%" PRIu32,
+                                    db->cnid_mysql_voluuid_str,
+                                    ntohl(id)) );
+        EC_NEG1( cnid_mysql_execute(db->cnid_mysql_con,
+                                    "DELETE FROM %s WHERE Did=%" PRIu32 " AND Name='%s'",
+                                    db->cnid_mysql_voluuid_str, ntohl(did), name) );
+        EC_NEG1( cnid_mysql_execute(db->cnid_mysql_con,
+                                    "DELETE FROM %s WHERE DevNo=%" PRIu64 " AND InodeNo=%" PRIu64,
+                                    db->cnid_mysql_voluuid_str, dev, ino) );
+
+        stmt_param_id = ntohl(id);
+        strncpy(stmt_param_name, name, sizeof(stmt_param_name));
+        stmt_param_name_len = len;
+        stmt_param_did = ntohl(did);
+        stmt_param_dev = dev;
+        stmt_param_ino = ino;
+
+        if (mysql_stmt_execute(db->cnid_put_stmt)) {
+            switch (mysql_stmt_errno(db->cnid_put_stmt)) {
+            case ER_DUP_ENTRY:
+                /*
+                 * Race condition:
+                 * between deletion and insert another process may have inserted
+                 * this entry.
+                 */
+                continue;
+            case CR_SERVER_LOST:
+                close_prepared_stmt(db);
+                EC_ZERO( init_prepared_stmt(db) );
+                continue;
+            default:
+                EC_FAIL;
+            }
+        }
+        update_id = mysql_stmt_insert_id(db->cnid_put_stmt);
+    } while (update_id != ntohl(id));
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+
+cnid_t cnid_mysql_lookup(struct _cnid_db *cdb,
+                         const struct stat *st,
+                         cnid_t did,
+                         const char *name,
+                         size_t len)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+    cnid_t id = CNID_INVALID;
+    bool have_result = false;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_lookup: Parameter error");
+        errno = CNID_ERR_PARAM;
+        EC_FAIL;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_lookup: Path name is too long");
+        errno = CNID_ERR_PATH;
+        EC_FAIL;
+    }
+
+    uint64_t dev = st->st_dev;
+    uint64_t ino = st->st_ino;
+    cnid_t hint = db->cnid_mysql_hint;
+
+    LOG(log_maxdebug, logtype_cnid, "cnid_mysql_lookup(did: %" PRIu32 ", name: \"%s\", hint: %" PRIu32 "): START",
+        ntohl(did), name, ntohl(hint));
+
+    strncpy(stmt_param_name, name, sizeof(stmt_param_name));
+    stmt_param_name_len = len;
+    stmt_param_did = ntohl(did);
+    stmt_param_dev = dev;
+    stmt_param_ino = ino;
+
+exec_stmt:
+    if (mysql_stmt_execute(db->cnid_lookup_stmt)) {
+        switch (mysql_stmt_errno(db->cnid_lookup_stmt)) {
+        case CR_SERVER_LOST:
+            close_prepared_stmt(db);
+            EC_ZERO( init_prepared_stmt(db) );
+            goto exec_stmt;
+        default:
+            EC_FAIL;
+        }
+    }
+    EC_ZERO_LOG( mysql_stmt_store_result(db->cnid_lookup_stmt) );
+    have_result = true;
+    EC_ZERO_LOG( mysql_stmt_bind_result(db->cnid_lookup_stmt, lookup_result) );
+
+    uint64_t retdev, retino;
+    cnid_t retid, retdid;
+    char *retname;
+
+    switch (mysql_stmt_num_rows(db->cnid_lookup_stmt)) {
+
+    case 0:
+        /* not found */
+        LOG(log_debug, logtype_cnid, "cnid_mysql_lookup: name: '%s', did: %u is not in the CNID database", 
+            name, ntohl(did));
+        errno = CNID_DBD_RES_NOTFOUND;
+        EC_FAIL;
+
+    case 1:
+        /* either both OR clauses matched the same id or only one matched, handled below */
+        EC_ZERO( mysql_stmt_fetch(db->cnid_lookup_stmt) );
+        break;
+
+    case 2:
+        /* a mismatch, delete both and return not found */
+        while (mysql_stmt_fetch(db->cnid_lookup_stmt) == 0) {
+            if (cnid_mysql_delete(cdb, htonl((cnid_t)lookup_result_id))) {
+                LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+                errno = CNID_ERR_DB;
+                EC_FAIL;
+            }
+        }
+        errno = CNID_DBD_RES_NOTFOUND;
+        EC_FAIL;
+
+    default:
+        errno = CNID_ERR_DB;
+        EC_FAIL;
+    }
+
+    retid = htonl(lookup_result_id);
+    retdid = htonl(lookup_result_did);
+    retname = lookup_result_name;
+    retdev = lookup_result_dev;
+    retino = lookup_result_ino;
+
+    if (retdid != did || STRCMP(retname, !=, name)) {
+        LOG(log_debug, logtype_cnid,
+            "cnid_mysql_lookup(CNID hint: %" PRIu32 ", DID: %" PRIu32 ", name: \"%s\"): server side mv oder reused inode",
+            ntohl(hint), ntohl(did), name);
+        if (hint != retid) {
+            if (cnid_mysql_delete(cdb, retid) != 0) {
+                LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+                errno = CNID_ERR_DB;
+                EC_FAIL;
+            }
+            errno = CNID_DBD_RES_NOTFOUND;
+            EC_FAIL;
+        }
+        LOG(log_debug, logtype_cnid, "cnid_mysql_lookup: server side mv, got hint, updating");
+        if (cnid_mysql_update(cdb, retid, st, did, name, len) != 0) {
+            LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+            errno = CNID_ERR_DB;
+            EC_FAIL;
+        }
+        id = retid;
+    } else if (retdev != dev || retino != ino) {
+        LOG(log_debug, logtype_cnid, "cnid_mysql_lookup(DID:%u, name: \"%s\"): changed dev/ino",
+            ntohl(did), name);
+        if (cnid_mysql_delete(cdb, retid) != 0) {
+            LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+            errno = CNID_ERR_DB;
+            EC_FAIL;
+        }
+        errno = CNID_DBD_RES_NOTFOUND;
+        EC_FAIL;
+    } else {
+        /* everythings good */
+        id = retid;
+    }
+
+EC_CLEANUP:
+    LOG(log_debug, logtype_cnid, "cnid_mysql_lookup: id: %" PRIu32, ntohl(id));
+    if (have_result)
+        mysql_stmt_free_result(db->cnid_lookup_stmt);
+    if (ret != 0)
+        id = CNID_INVALID;
+    return id;
+}
+
+cnid_t cnid_mysql_add(struct _cnid_db *cdb,
+                      const struct stat *st,
+                      cnid_t did,
+                      const char *name,
+                      size_t len,
+                      cnid_t hint)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+    cnid_t id = CNID_INVALID;
+    MYSQL_RES *result = NULL;
+    MYSQL_STMT *stmt;
+    my_ulonglong lastid;
+
+    if (!cdb || !(db = cdb->_private) || !st || !name) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_add: Parameter error");
+        errno = CNID_ERR_PARAM;
+        EC_FAIL;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_add: Path name is too long");
+        errno = CNID_ERR_PATH;
+        EC_FAIL;
+    }
+
+    uint64_t dev = st->st_dev;
+    uint64_t ino = st->st_ino;
+    db->cnid_mysql_hint = hint;
+
+    LOG(log_maxdebug, logtype_cnid, "cnid_mysql_add(did: %" PRIu32 ", name: \"%s\", hint: %" PRIu32 "): START",
+        ntohl(did), name, ntohl(hint));
+
+    do {
+        if ((id = cnid_mysql_lookup(cdb, st, did, name, len)) == CNID_INVALID) {
+            if (errno == CNID_ERR_DB)
+                EC_FAIL;
+            /*
+             * If the CNID set overflowed before (CNID_MYSQL_FLAG_DEPLETED)
+             * ignore the CNID "hint" taken from the AppleDouble file
+             */
+            if (!db->cnid_mysql_hint || (db->cnid_mysql_flags & CNID_MYSQL_FLAG_DEPLETED)) {
+                stmt = db->cnid_add_stmt;
+            } else {
+                stmt = db->cnid_put_stmt;
+                stmt_param_id = ntohl(db->cnid_mysql_hint);
+            }
+            strncpy(stmt_param_name, name, sizeof(stmt_param_name));
+            stmt_param_name_len = len;
+            stmt_param_did = ntohl(did);
+            stmt_param_dev = dev;
+            stmt_param_ino = ino;
+
+            if (mysql_stmt_execute(stmt)) {
+                switch (mysql_stmt_errno(stmt)) {
+                case ER_DUP_ENTRY:
+                    break;
+                case CR_SERVER_LOST:
+                    close_prepared_stmt(db);
+                    EC_ZERO( init_prepared_stmt(db) );
+                    continue;
+                default:
+                    EC_FAIL;
+                }
+                /*
+                 * Race condition:
+                 * between lookup and insert another process may have inserted
+                 * this entry.
+                 */
+                if (db->cnid_mysql_hint)
+                    db->cnid_mysql_hint = CNID_INVALID;
+                continue;
+            }
+
+            lastid = mysql_stmt_insert_id(stmt);
+
+            if (lastid > 0xffffffff) {
+                /* CNID set ist depleted, restart from scratch */
+                EC_NEG1( cnid_mysql_execute(db->cnid_mysql_con,
+                                            "START TRANSACTION;"
+                                            "UPDATE volumes SET Depleted=1 WHERE VolUUID='%s';"
+                                            "TRUNCATE TABLE %s;"
+                                            "ALTER TABLE %s AUTO_INCREMENT = 17;" 
+                                            "COMMIT;",
+                                            db->cnid_mysql_voluuid_str,
+                                            db->cnid_mysql_voluuid_str,
+                                            db->cnid_mysql_voluuid_str) );
+                db->cnid_mysql_flags |= CNID_MYSQL_FLAG_DEPLETED;
+                hint = CNID_INVALID;
+                do {
+                    result = mysql_store_result(db->cnid_mysql_con);
+                    if (result)
+                        mysql_free_result(result);
+                } while (mysql_next_result(db->cnid_mysql_con) == 0);
+                continue;
+            }
+
+            /* Finally assign our result */
+            id = htonl((uint32_t)lastid);
+        }
+    } while (id == CNID_INVALID);
+
+EC_CLEANUP:
+    LOG(log_debug, logtype_cnid, "cnid_mysql_add: id: %" PRIu32, ntohl(id));
+
+    if (result)
+        mysql_free_result(result);
+    return id;
+}
+
+cnid_t cnid_mysql_get(struct _cnid_db *cdb, cnid_t did, const char *name, size_t len)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+    cnid_t id = CNID_INVALID;
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+
+    if (!cdb || !(db = cdb->_private) || !name) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_get: Parameter error");
+        errno = CNID_ERR_PARAM;
+        EC_FAIL;
+    }
+
+    if (len > MAXPATHLEN) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_get: name is too long");
+        errno = CNID_ERR_PATH;
+        return CNID_INVALID;
+    }
+
+    LOG(log_debug, logtype_cnid, "cnid_mysql_get(did: %" PRIu32 ", name: \"%s\"): START",
+        ntohl(did),name);
+
+    EC_NEG1( cnid_mysql_execute(db->cnid_mysql_con,
+                                "SELECT Id FROM %s "
+                                "WHERE Name='%s' AND Did=%" PRIu32,
+                                db->cnid_mysql_voluuid_str,
+                                name,
+                                ntohl(did)) );
+
+    if ((result = mysql_store_result(db->cnid_mysql_con)) == NULL) {
+        LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+        errno = CNID_ERR_DB;
+        EC_FAIL;
+    }
+
+    if (mysql_num_rows(result)) {
+        row = mysql_fetch_row(result);
+        id = htonl(atoi(row[0]));
+    }
+
+EC_CLEANUP:
+    LOG(log_debug, logtype_cnid, "cnid_mysql_get: id: %" PRIu32, ntohl(id));
+
+    if (result)
+        mysql_free_result(result);
+
+    return id;
+}
+
+char *cnid_mysql_resolve(struct _cnid_db *cdb, cnid_t *id, void *buffer, size_t len)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+
+    if (!cdb || !(db = cdb->_private)) {
+        LOG(log_error, logtype_cnid, "cnid_mysql_get: Parameter error");
+        errno = CNID_ERR_PARAM;
+        EC_FAIL;
+    }
+
+    EC_NEG1( cnid_mysql_execute(
+                 db->cnid_mysql_con,
+                 "SELECT Did,Name FROM %s WHERE Id=%" PRIu32,
+                 db->cnid_mysql_voluuid_str, ntohl(*id)) );
+
+    EC_NULL( result = mysql_store_result(db->cnid_mysql_con) );
+
+    if (mysql_num_rows(result) != 1)
+        EC_FAIL;
+
+    row = mysql_fetch_row(result);
+
+    *id = htonl(atoi(row[0]));
+    strncpy(buffer, row[1], len);
+
+EC_CLEANUP:             
+    if (result)
+        mysql_free_result(result);
+
+    if (ret != 0) {
+        *id = CNID_INVALID;
+        return NULL;
+    }
+    return buffer;
+}
+
+/**
+ * Caller passes buffer where we will store the db stamp
+ **/
+int cnid_mysql_getstamp(struct _cnid_db *cdb, void *buffer, const size_t len)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+
+    if (!cdb || !(db = cdb->_private)) {
+        LOG(log_error, logtype_cnid, "cnid_find: Parameter error");
+        errno = CNID_ERR_PARAM;
+        return CNID_INVALID;
+    }
+
+    if (!buffer)
+        EC_EXIT_STATUS(0);
+
+    if (cnid_mysql_execute(db->cnid_mysql_con,
+                           "SELECT Stamp FROM volumes WHERE VolPath='%s'",
+                           db->cnid_mysql_volname)) {
+        if (mysql_errno(db->cnid_mysql_con) != ER_DUP_ENTRY) {
+            LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+            EC_FAIL;
+        }
+    }
+
+    if ((result = mysql_store_result(db->cnid_mysql_con)) == NULL) {
+        LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+        errno = CNID_ERR_DB;
+        EC_FAIL;
+    }
+    if (!mysql_num_rows(result)) {
+        LOG(log_error, logtype_cnid, "Can't get DB stamp for volumes \"%s\"", db->cnid_mysql_volname);
+        EC_FAIL;
+    }
+    row = mysql_fetch_row(result);
+    memcpy(buffer, row[0], len);
+
+EC_CLEANUP:
+    if (result)
+        mysql_free_result(result);
+    EC_EXIT;
+}
+
+
+int cnid_mysql_find(struct _cnid_db *cdb, const char *name, size_t namelen, void *buffer, size_t buflen)
+{
+    LOG(log_error, logtype_cnid,
+        "cnid_mysql_find(\"%s\"): not supported with MySQL CNID backend", name);
+    return -1;
+}
+
+cnid_t cnid_mysql_rebuild_add(struct _cnid_db *cdb, const struct stat *st,
+                              cnid_t did, const char *name, size_t len, cnid_t hint)
+{
+    LOG(log_error, logtype_cnid,
+        "cnid_mysql_rebuild_add(\"%s\"): not supported with MySQL CNID backend", name);
+    return CNID_INVALID;
+}
+
+int cnid_mysql_wipe(struct _cnid_db *cdb)
+{
+    EC_INIT;
+    CNID_mysql_private *db;
+    MYSQL_RES *result = NULL;
+
+    if (!cdb || !(db = cdb->_private)) {
+        LOG(log_error, logtype_cnid, "cnid_wipe: Parameter error");
+        errno = CNID_ERR_PARAM;
+        return -1;
+    }
+
+    LOG(log_debug, logtype_cnid, "cnid_dbd_wipe");
+
+    EC_NEG1( cnid_mysql_execute(
+                 db->cnid_mysql_con,
+                 "START TRANSACTION;"
+                 "UPDATE volumes SET Depleted=0 WHERE VolUUID='%s';"
+                 "TRUNCATE TABLE %s;"
+                 "ALTER TABLE %s AUTO_INCREMENT = 17;"
+                 "COMMIT;",
+                 db->cnid_mysql_voluuid_str,
+                 db->cnid_mysql_voluuid_str,
+                 db->cnid_mysql_voluuid_str) );
+
+    do {
+        result = mysql_store_result(db->cnid_mysql_con);
+        if (result)
+            mysql_free_result(result);
+    } while (mysql_next_result(db->cnid_mysql_con) == 0);
+
+EC_CLEANUP:
+    EC_EXIT;
+}
+
+static struct _cnid_db *cnid_mysql_new(const char *volpath)
+{
+    struct _cnid_db *cdb;
+
+    if ((cdb = (struct _cnid_db *)calloc(1, sizeof(struct _cnid_db))) == NULL)
+        return NULL;
+
+    if ((cdb->volpath = strdup(volpath)) == NULL) {
+        free(cdb);
+        return NULL;
+    }
+
+    cdb->flags = CNID_FLAG_PERSISTENT | CNID_FLAG_LAZY_INIT;
+    cdb->cnid_add = cnid_mysql_add;
+    cdb->cnid_delete = cnid_mysql_delete;
+    cdb->cnid_get = cnid_mysql_get;
+    cdb->cnid_lookup = cnid_mysql_lookup;
+    cdb->cnid_find = cnid_mysql_find;
+    cdb->cnid_nextid = NULL;
+    cdb->cnid_resolve = cnid_mysql_resolve;
+    cdb->cnid_getstamp = cnid_mysql_getstamp;
+    cdb->cnid_update = cnid_mysql_update;
+    cdb->cnid_rebuild_add = cnid_mysql_rebuild_add;
+    cdb->cnid_close = cnid_mysql_close;
+    cdb->cnid_wipe = cnid_mysql_wipe;
+    return cdb;
+}
+
+static const char *printuuid(const unsigned char *uuid) {
+    static char uuidstring[64];
+    const char *uuidmask;
+    int i = 0;
+    unsigned char c;
+
+    while ((c = *uuid)) {
+        uuid++;
+        sprintf(uuidstring + i, "%02X", c);
+        i += 2;
+    }
+    uuidstring[i] = 0;
+    return uuidstring;
+}
+
+/* ---------------------- */
+struct _cnid_db *cnid_mysql_open(struct cnid_open_args *args)
+{
+    EC_INIT;
+    CNID_mysql_private *db = NULL;
+    struct _cnid_db *cdb = NULL;
+    MYSQL_RES *result = NULL;
+    MYSQL_ROW row;
+
+    EC_NULL( cdb = cnid_mysql_new(args->dir) );
+    EC_NULL( db = (CNID_mysql_private *)calloc(1, sizeof(CNID_mysql_private)) );
+    cdb->_private = db;
+
+    db->cnid_mysql_volname = strdup(args->dir); /* db_dir contains the volume name */
+    db->cnid_mysql_magic = CNID_DB_MAGIC;
+    db->cnid_mysql_obj = args->obj;
+    memcpy(db->cnid_mysql_voluuid, args->voluuid, sizeof(atalk_uuid_t));
+    db->cnid_mysql_voluuid_str = strdup(printuuid(db->cnid_mysql_voluuid));
+
+    /* Initialize and connect to MySQL server */
+    EC_NULL( db->cnid_mysql_con = mysql_init(NULL) );
+    my_bool my_recon = true;
+    EC_ZERO( mysql_options(db->cnid_mysql_con, MYSQL_OPT_RECONNECT, &my_recon) );
+    int my_timeout = 600;
+    EC_ZERO( mysql_options(db->cnid_mysql_con, MYSQL_OPT_CONNECT_TIMEOUT, &my_timeout) );
+
+    const AFPObj *obj = db->cnid_mysql_obj;
+
+    EC_NULL( mysql_real_connect(db->cnid_mysql_con,
+                                obj->options.cnid_mysql_host,
+                                obj->options.cnid_mysql_user,
+                                obj->options.cnid_mysql_pw,
+                                obj->options.cnid_mysql_db,
+                                0, NULL, CLIENT_MULTI_STATEMENTS));
+
+    /* Add volume to volume table */
+    if (cnid_mysql_execute(db->cnid_mysql_con,
+                           "CREATE TABLE IF NOT EXISTS volumes"
+                           "(VolUUID CHAR(32) PRIMARY KEY,VolPath TEXT(4096),Stamp BINARY(8),Depleted INT, INDEX(VolPath(64)))")) {
+        LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+        EC_FAIL;
+    }
+    time_t now = time(NULL);
+    char stamp[8];
+    memset(stamp, 0, 8);
+    memcpy(stamp, &now, sizeof(time_t));
+    char blob[16+1];
+    mysql_real_escape_string(db->cnid_mysql_con, blob, stamp, 8);
+
+    if (cnid_mysql_execute(db->cnid_mysql_con,
+                           "INSERT INTO volumes (VolUUID,Volpath,Stamp,Depleted) "
+                           "VALUES('%s','%s','%s',0)",
+                           db->cnid_mysql_voluuid_str,
+                           db->cnid_mysql_volname,
+                           blob)) {
+        if (mysql_errno(db->cnid_mysql_con) != ER_DUP_ENTRY) {
+            LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+            EC_FAIL;
+        }
+    }
+
+    /*
+     * Check whether CNID set overflowed before.
+     * If that's the case, in cnid_mysql_add() we'll ignore the CNID "hint" taken from the
+     * AppleDouble file.
+     */
+    if (cnid_mysql_execute(db->cnid_mysql_con,
+                           "SELECT Depleted FROM volumes WHERE VolUUID='%s'",
+                           db->cnid_mysql_voluuid_str)) {
+        LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+        EC_FAIL;
+    }
+    if ((result = mysql_store_result(db->cnid_mysql_con)) == NULL) {
+        LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+        errno = CNID_ERR_DB;
+        EC_FAIL;
+    }
+    if (mysql_num_rows(result)) {
+        row = mysql_fetch_row(result);
+        int depleted = atoi(row[0]);
+        if (depleted)
+            db->cnid_mysql_flags |= CNID_MYSQL_FLAG_DEPLETED;
+    }
+    mysql_free_result(result);
+    result = NULL;
+
+    /* Create volume table */
+    if (cnid_mysql_execute(db->cnid_mysql_con,
+                           "CREATE TABLE IF NOT EXISTS %s"
+                           "(Id BIGINT UNSIGNED PRIMARY KEY AUTO_INCREMENT,"
+                           "Name VARCHAR(255) NOT NULL,"
+                           "Did INT UNSIGNED NOT NULL,"
+                           "DevNo BIGINT UNSIGNED NOT NULL,"
+                           "InodeNo BIGINT UNSIGNED NOT NULL,"
+                           "UNIQUE DidName(Did, Name), UNIQUE DevIno(DevNo, InodeNo)) "
+                           "AUTO_INCREMENT=17",
+                           db->cnid_mysql_voluuid_str)) {
+        LOG(log_error, logtype_cnid, "MySQL query error: %s", mysql_error(db->cnid_mysql_con));
+        EC_FAIL;
+    }
+
+    EC_ZERO( init_prepared_stmt(db) );
+
+    LOG(log_debug, logtype_cnid, "Finished initializing MySQL CNID module for volume '%s'",
+        db->cnid_mysql_volname);
+
+EC_CLEANUP:
+    if (result)
+        mysql_free_result(result);
+    if (ret != 0) {
+        if (cdb) {
+            if (cdb->volpath != NULL) {
+                free(cdb->volpath);
+            }
+            free(cdb);
+        }
+        cdb = NULL;
+        if (db)
+            free(db);
+    }
+    return cdb;
+}
+
+struct _cnid_module cnid_mysql_module = {
+    "mysql",
+    {NULL, NULL},
+    cnid_mysql_open,
+    0
+};
index d1b46874329ce630bfb2bcb12524de847f86a5b9..fa6fb8b57ca2084a95bf055af256fffd784b5e33 100644 (file)
@@ -1800,6 +1800,10 @@ int afp_config_parse(AFPObj *AFPObj, char *processname)
     options->mimicmodel     = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "mimic model",    NULL);
     options->adminauthuser  = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "admin auth user",NULL);
     options->ignored_attr   = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "ignored attributes", NULL);
+    options->cnid_mysql_host = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "cnid mysql host", NULL);
+    options->cnid_mysql_user = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "cnid mysql user", NULL);
+    options->cnid_mysql_pw  = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "cnid mysql pw", NULL);
+    options->cnid_mysql_db  = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "cnid mysql db", NULL);
     options->connections    = atalk_iniparser_getint   (config, INISEC_GLOBAL, "max connections",200);
     options->passwdminlen   = atalk_iniparser_getint   (config, INISEC_GLOBAL, "passwd minlen",  0);
     options->tickleval      = atalk_iniparser_getint   (config, INISEC_GLOBAL, "tickleval",      30);
index 1e0366142876fa9dd5c87f69b19f035f21fb4a03..c87e457c598c0832985228832bfeb867e7f57360 100644 (file)
@@ -108,6 +108,39 @@ AC_DEFUN([AC_NETATALK_CNID], [
     fi
     AM_CONDITIONAL(USE_TDB_BACKEND, test x"$use_tdb_backend" = x"yes")
 
+    dnl Check for mysql CNID backend
+    AC_ARG_VAR(MYSQL_CFLAGS, [C compiler flags for MySQL, overriding checks])
+    AC_ARG_VAR(MYSQL_LIBS, [linker flags for MySQL, overriding checks])
+
+    AC_MSG_CHECKING([MySQL library and headers])
+    AC_ARG_WITH(
+        mysql-config,
+        [AS_HELP_STRING([--with-mysql-config=PATH],[Path to mysql-config binary (default: mysql_config)])],
+        MYSQL_CONFIG=$withval
+    )
+
+    if test -z "$MYSQL_CONFIG" -a -z "$MYSQL_CFLAGS" -a -z "$MYSQL_LIBS" ; then
+        AC_PATH_PROG(MYSQL_CONFIG, mysql_config)
+    fi
+
+    if test -x "$MYSQL_CONFIG" ; then
+        AC_MSG_RESULT([$MYSQL_CONFIG])
+        MYSQL_CFLAGS="`$MYSQL_CONFIG --cflags`"
+        MYSQL_LIBS="`$MYSQL_CONFIG --libs`"
+        ac_cv_with_cnid_mysql="yes"
+    elif test -n "$MYSQL_CFLAGS" -a -n "$MYSQL_LIBS" ; then
+        ac_cv_with_cnid_mysql="yes"
+    fi
+
+    if test x"$ac_cv_with_cnid_mysql" = x"yes" ; then
+        compiled_backends="$compiled_backends mysql"
+        AC_DEFINE(CNID_BACKEND_MYSQL, 1, [whether the MySQL CNID module is available])
+    fi
+
+    AC_SUBST(MYSQL_CFLAGS)
+    AC_SUBST(MYSQL_LIBS)
+    AM_CONDITIONAL(USE_MYSQL_BACKEND, test x"$ac_cv_with_cnid_mysql" = x"yes")
+
     dnl Set default DID scheme
     AC_MSG_CHECKING([default DID scheme])
     AC_ARG_WITH(cnid-default-backend,
index d3261192cc6694bada5ba14a23c9e23859c7906a..de8aaa0cb8fa9493a705e134335f03c55c61d612 100644 (file)
@@ -148,7 +148,6 @@ AC_DEFUN([AC_NETATALK_LIBS_SUMMARY], [
                AC_MSG_RESULT([        LIBS   = $LIBEVENT_CFLAGS])
                AC_MSG_RESULT([        CFLAGS = $LIBEVENT_LDFLAGS])
     fi
-
     AC_MSG_RESULT([    TDB:])
     if test x"$use_bundled_tdb" = x"yes"; then
                AC_MSG_RESULT([        bundled])
@@ -156,4 +155,9 @@ AC_DEFUN([AC_NETATALK_LIBS_SUMMARY], [
                AC_MSG_RESULT([        LIBS   = $TDB_LIBS])
                AC_MSG_RESULT([        CFLAGS = $TDB_CFLAGS])
     fi
+       if test x"$ac_cv_with_cnid_mysql" = x"yes"; then
+               AC_MSG_RESULT([    MySQL:])
+               AC_MSG_RESULT([        LIBS   = $MYSQL_LIBS])
+               AC_MSG_RESULT([        CFLAGS = $MYSQL_CFLAGS])
+       fi
 ])
index 6e7c2f46aec3620acd52822430fbcdeedb4cf126..f5109b8dd3f0658fa192e4c6f5cef851174335d4 100644 (file)
@@ -63,7 +63,7 @@ test_CFLAGS = \
 
 test_LDADD = \
        $(top_builddir)/libatalk/libatalk.la \
-       @LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@
+       @LIBGCRYPT_LIBS@ @QUOTA_LIBS@ @WRAP_LIBS@ @LIBADD_DL@ @ACL_LIBS@ @ZEROCONF_LIBS@ @PTHREAD_LIBS@ @GSSAPI_LIBS@ @KRB5_LIBS@ @MYSQL_LIBS@
 
 test_LDFLAGS = -export-dynamic