From: Ralph Boehme Date: Sun, 13 Oct 2013 14:16:54 +0000 (+0200) Subject: New MySQL CNID backend X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=f254fd618b53e97cc5382b23709d4f3de1e70b41 New MySQL CNID backend 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. --- diff --git a/NEWS b/NEWS index 504d2c08..0a4b5d9c 100644 --- 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 ================ diff --git a/bin/ad/Makefile.am b/bin/ad/Makefile.am index 5c3f47b6..e7b2c147 100644 --- a/bin/ad/Makefile.am +++ b/bin/ad/Makefile.am @@ -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 diff --git a/bin/ad/ad_find.c b/bin/ad/ad_find.c index 88a46752..093414a1 100644 --- a/bin/ad/ad_find.c +++ b/bin/ad/ad_find.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include diff --git a/bin/ad/ad_util.c b/bin/ad/ad_util.c index 7d4d2fb9..782bbffa 100644 --- a/bin/ad/ad_util.c +++ b/bin/ad/ad_util.c @@ -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, diff --git a/bin/afppasswd/Makefile.am b/bin/afppasswd/Makefile.am index cab2df66..578eac1b 100644 --- a/bin/afppasswd/Makefile.am +++ b/bin/afppasswd/Makefile.am @@ -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\" diff --git a/bin/misc/Makefile.am b/bin/misc/Makefile.am index 5b2fd4e3..2cbb8d0a 100644 --- a/bin/misc/Makefile.am +++ b/bin/misc/Makefile.am @@ -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@ diff --git a/bin/uniconv/Makefile.am b/bin/uniconv/Makefile.am index 202e7227..58bbd0be 100644 --- a/bin/uniconv/Makefile.am +++ b/bin/uniconv/Makefile.am @@ -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@ diff --git a/bin/uniconv/uniconv.c b/bin/uniconv/uniconv.c index 8a786a60..93439cef 100644 --- a/bin/uniconv/uniconv.c +++ b/bin/uniconv/uniconv.c @@ -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; diff --git a/configure.ac b/configure.ac index b3dba043..8902ae1e 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am index 8cfe75a4..a0b210e1 100644 --- a/etc/afpd/Makefile.am +++ b/etc/afpd/Makefile.am @@ -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 diff --git a/etc/afpd/afp_options.c b/etc/afpd/afp_options.c index 932e6a65..f06bfb37 100644 --- a/etc/afpd/afp_options.c +++ b/etc/afpd/afp_options.c @@ -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( "" ); } diff --git a/etc/afpd/catsearch.c b/etc/afpd/catsearch.c index 63a9607c..bec7b152 100644 --- a/etc/afpd/catsearch.c +++ b/etc/afpd/catsearch.c @@ -46,7 +46,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/etc/afpd/file.c b/etc/afpd/file.c index edb55ea3..cb8a968a 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -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; diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 4efa659f..07cfb42b 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -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) { diff --git a/etc/cnid_dbd/Makefile.am b/etc/cnid_dbd/Makefile.am index 3ebcbebb..a9133d9c 100644 --- a/etc/cnid_dbd/Makefile.am +++ b/etc/cnid_dbd/Makefile.am @@ -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 diff --git a/etc/cnid_dbd/cmd_dbd.c b/etc/cnid_dbd/cmd_dbd.c index 31d74e6c..4018eecc 100644 --- a/etc/cnid_dbd/cmd_dbd.c +++ b/etc/cnid_dbd/cmd_dbd.c @@ -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); } diff --git a/etc/cnid_dbd/cnid_metad.c b/etc/cnid_dbd/cnid_metad.c index 3d71094b..42b398f7 100644 --- a/etc/cnid_dbd/cnid_metad.c +++ b/etc/cnid_dbd/cnid_metad.c @@ -87,7 +87,7 @@ #include #include -#include +#include #include #include #include diff --git a/etc/cnid_dbd/comm.c b/etc/cnid_dbd/comm.c index 7cd8f559..28fab0e4 100644 --- a/etc/cnid_dbd/comm.c +++ b/etc/cnid_dbd/comm.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include "db_param.h" diff --git a/etc/cnid_dbd/comm.h b/etc/cnid_dbd/comm.h index 46d91fc1..22617770 100644 --- a/etc/cnid_dbd/comm.h +++ b/etc/cnid_dbd/comm.h @@ -9,7 +9,7 @@ /* number of seconds to try reading in readt */ #define CNID_DBD_TIMEOUT 1 -#include +#include extern int comm_init (struct db_param *, int, int); diff --git a/etc/cnid_dbd/dbd.h b/etc/cnid_dbd/dbd.h index 7b8da1ca..ab532d80 100644 --- a/etc/cnid_dbd/dbd.h +++ b/etc/cnid_dbd/dbd.h @@ -9,7 +9,7 @@ #include -#include +#include 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); diff --git a/etc/cnid_dbd/dbd_add.c b/etc/cnid_dbd/dbd_add.c index db9c6cc2..3af72fa8 100644 --- a/etc/cnid_dbd/dbd_add.c +++ b/etc/cnid_dbd/dbd_add.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include #include diff --git a/etc/cnid_dbd/dbd_dbcheck.c b/etc/cnid_dbd/dbd_dbcheck.c index 98ce2210..27f9021e 100644 --- a/etc/cnid_dbd/dbd_dbcheck.c +++ b/etc/cnid_dbd/dbd_dbcheck.c @@ -15,7 +15,7 @@ #include #include -#include +#include #include "pack.h" #include "dbif.h" diff --git a/etc/cnid_dbd/dbd_delete.c b/etc/cnid_dbd/dbd_delete.c index f34a9d50..59109420 100644 --- a/etc/cnid_dbd/dbd_delete.c +++ b/etc/cnid_dbd/dbd_delete.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "dbif.h" #include "dbd.h" diff --git a/etc/cnid_dbd/dbd_get.c b/etc/cnid_dbd/dbd_get.c index c1c7bb8c..07d82da2 100644 --- a/etc/cnid_dbd/dbd_get.c +++ b/etc/cnid_dbd/dbd_get.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include "dbif.h" diff --git a/etc/cnid_dbd/dbd_getstamp.c b/etc/cnid_dbd/dbd_getstamp.c index ffba3972..27270c76 100644 --- a/etc/cnid_dbd/dbd_getstamp.c +++ b/etc/cnid_dbd/dbd_getstamp.c @@ -14,7 +14,7 @@ #include #include -#include +#include #include "dbif.h" #include "dbd.h" diff --git a/etc/cnid_dbd/dbd_lookup.c b/etc/cnid_dbd/dbd_lookup.c index f77b9fc2..9ff4e411 100644 --- a/etc/cnid_dbd/dbd_lookup.c +++ b/etc/cnid_dbd/dbd_lookup.c @@ -118,7 +118,7 @@ to be safe we must assign new CNIDs to both files. #include #include -#include +#include #include #include "pack.h" diff --git a/etc/cnid_dbd/dbd_rebuild_add.c b/etc/cnid_dbd/dbd_rebuild_add.c index f1bf7aca..3aee1c94 100644 --- a/etc/cnid_dbd/dbd_rebuild_add.c +++ b/etc/cnid_dbd/dbd_rebuild_add.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "pack.h" #include "dbif.h" diff --git a/etc/cnid_dbd/dbd_resolve.c b/etc/cnid_dbd/dbd_resolve.c index 53407757..20ff8f7b 100644 --- a/etc/cnid_dbd/dbd_resolve.c +++ b/etc/cnid_dbd/dbd_resolve.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "dbif.h" #include "dbd.h" diff --git a/etc/cnid_dbd/dbd_search.c b/etc/cnid_dbd/dbd_search.c index 66979424..685eef67 100644 --- a/etc/cnid_dbd/dbd_search.c +++ b/etc/cnid_dbd/dbd_search.c @@ -12,7 +12,7 @@ #include #include -#include +#include #include "dbif.h" #include "dbd.h" diff --git a/etc/cnid_dbd/dbd_update.c b/etc/cnid_dbd/dbd_update.c index e8abf5d2..7a95bfe7 100644 --- a/etc/cnid_dbd/dbd_update.c +++ b/etc/cnid_dbd/dbd_update.c @@ -13,7 +13,7 @@ #include #include -#include +#include #include "pack.h" diff --git a/etc/cnid_dbd/main.c b/etc/cnid_dbd/main.c index 0067504a..97dcd557 100644 --- a/etc/cnid_dbd/main.c +++ b/etc/cnid_dbd/main.c @@ -22,7 +22,7 @@ #include #include -#include +#include #include #include #include diff --git a/etc/cnid_dbd/pack.c b/etc/cnid_dbd/pack.c index 2e9a32ee..dc61dded 100644 --- a/etc/cnid_dbd/pack.c +++ b/etc/cnid_dbd/pack.c @@ -17,7 +17,7 @@ #include #include -#include +#include #include #include "pack.h" diff --git a/etc/cnid_dbd/pack.h b/etc/cnid_dbd/pack.h index 9894d49a..5566bea2 100644 --- a/etc/cnid_dbd/pack.h +++ b/etc/cnid_dbd/pack.h @@ -8,7 +8,7 @@ #define CNID_DBD_PACK_H 1 #include -#include +#include extern unsigned char *pack_cnid_data(struct cnid_dbd_rqst *); extern int didname(DB *dbp, const DBT *pkey, const DBT *pdata, DBT *skey); diff --git a/etc/cnid_dbd/usockfd.h b/etc/cnid_dbd/usockfd.h index 27bde63c..44f01ae2 100644 --- a/etc/cnid_dbd/usockfd.h +++ b/etc/cnid_dbd/usockfd.h @@ -9,7 +9,7 @@ -#include +#include extern int usockfd_create (char *, mode_t, int); diff --git a/etc/netatalk/Makefile.am b/etc/netatalk/Makefile.am index 6cf95eb6..ca3e163f 100644 --- a/etc/netatalk/Makefile.am +++ b/etc/netatalk/Makefile.am @@ -12,6 +12,7 @@ netatalk_CFLAGS = \ -D_PATH_CNID_METAD=\"$(sbindir)/cnid_metad\" netatalk_LDADD = \ + @MYSQL_LIBS@ \ $(top_builddir)/libatalk/libatalk.la netatalk_LDFLAGS = diff --git a/etc/spotlight/Makefile.am b/etc/spotlight/Makefile.am index 7fd2721a..60e0c25b 100644 --- a/etc/spotlight/Makefile.am +++ b/etc/spotlight/Makefile.am @@ -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 diff --git a/include/atalk/Makefile.am b/include/atalk/Makefile.am index 2f63e0f6..550741d6 100644 --- a/include/atalk/Makefile.am +++ b/include/atalk/Makefile.am @@ -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 \ diff --git a/include/atalk/cnid.h b/include/atalk/cnid.h index ba0b62fa..9c8e0bac 100644 --- a/include/atalk/cnid.h +++ b/include/atalk/cnid.h @@ -24,6 +24,7 @@ #include #include +#include /* 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 index 00000000..8aab3e05 --- /dev/null +++ b/include/atalk/cnid_bdb_private.h @@ -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 +#include +#include + +#include + +#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 index b61f7a8c..00000000 --- a/include/atalk/cnid_dbd_private.h +++ /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 -#include -#include - -#include - -#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 index 00000000..6affaf7a --- /dev/null +++ b/include/atalk/cnid_mysql_private.h @@ -0,0 +1,23 @@ +#ifndef _ATALK_CNID_MYSQL_PRIVATE_H +#define _ATALK_CNID_MYSQL_PRIVATE_H 1 + +#include +#include + +#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 diff --git a/include/atalk/globals.h b/include/atalk/globals.h index 8944ec86..21b8b4e8 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -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; }; diff --git a/libatalk/Makefile.am b/libatalk/Makefile.am index d8733b35..3220b89a 100644 --- a/libatalk/Makefile.am +++ b/libatalk/Makefile.am @@ -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 \ diff --git a/libatalk/cnid/Makefile.am b/libatalk/cnid/Makefile.am index d1051e67..5c9dd52c 100644 --- a/libatalk/cnid/Makefile.am +++ b/libatalk/cnid/Makefile.am @@ -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) diff --git a/libatalk/cnid/cnid.c b/libatalk/cnid/cnid.c index 7cf3af16..9212cacc 100644 --- a/libatalk/cnid/cnid.c +++ b/libatalk/cnid/cnid.c @@ -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)) { diff --git a/libatalk/cnid/cnid_init.c b/libatalk/cnid/cnid_init.c index 75fc5db3..03cad388 100644 --- a/libatalk/cnid/cnid_init.c +++ b/libatalk/cnid/cnid_init.c @@ -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 } diff --git a/libatalk/cnid/dbd/cnid_dbd.c b/libatalk/cnid/dbd/cnid_dbd.c index 3f0278ae..1b365065 100644 --- a/libatalk/cnid/dbd/cnid_dbd.c +++ b/libatalk/cnid/dbd/cnid_dbd.c @@ -31,7 +31,7 @@ #include #include #include -#include +#include #include #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 index 00000000..df688b20 --- /dev/null +++ b/libatalk/cnid/mysql/Makefile.am @@ -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 index 00000000..c661f9ac --- /dev/null +++ b/libatalk/cnid/mysql/cnid_mysql.c @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +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 +}; diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index d1b46874..fa6fb8b5 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -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); diff --git a/macros/cnid-backend.m4 b/macros/cnid-backend.m4 index 1e036614..c87e457c 100644 --- a/macros/cnid-backend.m4 +++ b/macros/cnid-backend.m4 @@ -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, diff --git a/macros/summary.m4 b/macros/summary.m4 index d3261192..de8aaa0c 100644 --- a/macros/summary.m4 +++ b/macros/summary.m4 @@ -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 ]) diff --git a/test/afpd/Makefile.am b/test/afpd/Makefile.am index 6e7c2f46..f5109b8d 100644 --- a/test/afpd/Makefile.am +++ b/test/afpd/Makefile.am @@ -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