Merge branch 'master' into wspp-schema
authorAndrew Tridgell <tridge@samba.org>
Tue, 31 Mar 2009 04:53:17 +0000 (15:53 +1100)
committerAndrew Tridgell <tridge@samba.org>
Tue, 31 Mar 2009 04:53:17 +0000 (15:53 +1100)
19 files changed:
docs-xml/smbdotconf/printing/cupsencrypt.xml [new file with mode: 0644]
lib/tdb/common/transaction.c
lib/tdb/configure.ac
lib/tdb/docs/README
lib/tdb/include/tdb.h
lib/tdb/tools/tdbtorture.c
source3/configure.in
source3/include/proto.h
source3/param/loadparm.c
source3/printing/print_cups.c
source3/smbd/dosmode.c
source4/dsdb/samdb/ldb_modules/partition.c
source4/lib/ldb/configure.ac
source4/lib/ldb/external/libtdb.m4
source4/lib/ldb/include/ldb_module.h
source4/lib/ldb/ldb.mk
source4/lib/ldb/ldb_tdb/ldb_tdb.c
source4/lib/ldb/ldb_tdb/ldb_tdb.h
source4/min_versions.m4

diff --git a/docs-xml/smbdotconf/printing/cupsencrypt.xml b/docs-xml/smbdotconf/printing/cupsencrypt.xml
new file mode 100644 (file)
index 0000000..f93b1c5
--- /dev/null
@@ -0,0 +1,25 @@
+<samba:parameter name="cups encrypt"
+       context="G"
+       type="enum"
+       advanced="1" print="1"
+       xmlns:samba="http://www.samba.org/samba/DTD/samba-doc">
+<description>
+       <para>
+       This parameter is only applicable if <smbconfoption name="printing"/>
+       is set to <constant>cups</constant> and if you use CUPS newer than
+       1.0.x.It is used to define whether or not Samba should use encryption
+       when talking to the CUPS server. Possible values are
+       <emphasis>auto</emphasis>, <emphasis>yes</emphasis> and
+       <emphasis>no</emphasis>
+       </para>
+
+       <para>
+       When set to auto we will try to do a TLS handshake on each CUPS
+       connection setup. If that fails, we will fall back to unencrypted
+       operation.
+       </para>
+
+</description>
+
+<value type="default">"no"</value>
+</samba:parameter>
index 7acda640c8d32338de6e8651971d5f848740aae6..1cb7063a38432750973b8017cdb1277894ae3d2e 100644 (file)
@@ -116,6 +116,10 @@ struct tdb_transaction {
           but don't create a new transaction */
        int nesting;
 
+       /* set when a prepare has already occurred */
+       bool prepared;
+       tdb_off_t magic_offset;
+
        /* old file size before transaction */
        tdb_len_t old_map_size;
 };
@@ -130,6 +134,14 @@ static int transaction_read(struct tdb_context *tdb, tdb_off_t off, void *buf,
 {
        uint32_t blk;
 
+       /* Only a commit is allowed on a prepared transaction */
+       if (tdb->transaction->prepared) {
+               tdb->ecode = TDB_ERR_EINVAL;
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_read: transaction already prepared, read not allowed\n"));
+               tdb->transaction->transaction_error = 1;
+               return -1;
+       }
+
        /* break it down into block sized ops */
        while (len + (off % tdb->transaction->block_size) > tdb->transaction->block_size) {
                tdb_len_t len2 = tdb->transaction->block_size - (off % tdb->transaction->block_size);
@@ -187,6 +199,14 @@ static int transaction_write(struct tdb_context *tdb, tdb_off_t off,
 {
        uint32_t blk;
 
+       /* Only a commit is allowed on a prepared transaction */
+       if (tdb->transaction->prepared) {
+               tdb->ecode = TDB_ERR_EINVAL;
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "transaction_write: transaction already prepared, write not allowed\n"));
+               tdb->transaction->transaction_error = 1;
+               return -1;
+       }
+
        /* if the write is to a hash head, then update the transaction
           hash heads */
        if (len == sizeof(tdb_off_t) && off >= FREELIST_TOP &&
@@ -497,12 +517,38 @@ fail:
 }
 
 
+/*
+  sync to disk
+*/
+static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
+{      
+       if (fsync(tdb->fd) != 0) {
+               tdb->ecode = TDB_ERR_IO;
+               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
+               return -1;
+       }
+#ifdef HAVE_MMAP
+       if (tdb->map_ptr) {
+               tdb_off_t moffset = offset & ~(tdb->page_size-1);
+               if (msync(moffset + (char *)tdb->map_ptr, 
+                         length + (offset - moffset), MS_SYNC) != 0) {
+                       tdb->ecode = TDB_ERR_IO;
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
+                                strerror(errno)));
+                       return -1;
+               }
+       }
+#endif
+       return 0;
+}
+
+
 /*
   cancel the current transaction
 */
 int tdb_transaction_cancel(struct tdb_context *tdb)
 {      
-       int i;
+       int i, ret = 0;
 
        if (tdb->transaction == NULL) {
                TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_cancel: no transaction\n"));
@@ -525,6 +571,18 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
        }
        SAFE_FREE(tdb->transaction->blocks);
 
+       if (tdb->transaction->magic_offset) {
+               const struct tdb_methods *methods = tdb->transaction->io_methods;
+               uint32_t zero = 0;
+
+               /* remove the recovery marker */
+               if (methods->tdb_write(tdb, tdb->transaction->magic_offset, &zero, 4) == -1 ||
+               transaction_sync(tdb, tdb->transaction->magic_offset, 4) == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_cancel: failed to remove recovery magic\n"));
+                       ret = -1;
+               }
+       }
+
        /* remove any global lock created during the transaction */
        if (tdb->global_lock.count != 0) {
                tdb_brlock(tdb, FREELIST_TOP, F_UNLCK, F_SETLKW, 0, 4*tdb->header.hash_size);
@@ -550,32 +608,7 @@ int tdb_transaction_cancel(struct tdb_context *tdb)
        SAFE_FREE(tdb->transaction->hash_heads);
        SAFE_FREE(tdb->transaction);
        
-       return 0;
-}
-
-/*
-  sync to disk
-*/
-static int transaction_sync(struct tdb_context *tdb, tdb_off_t offset, tdb_len_t length)
-{      
-       if (fsync(tdb->fd) != 0) {
-               tdb->ecode = TDB_ERR_IO;
-               TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: fsync failed\n"));
-               return -1;
-       }
-#ifdef HAVE_MMAP
-       if (tdb->map_ptr) {
-               tdb_off_t moffset = offset & ~(tdb->page_size-1);
-               if (msync(moffset + (char *)tdb->map_ptr, 
-                         length + (offset - moffset), MS_SYNC) != 0) {
-                       tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction: msync failed - %s\n",
-                                strerror(errno)));
-                       return -1;
-               }
-       }
-#endif
-       return 0;
+       return ret;
 }
 
 
@@ -826,36 +859,39 @@ static int transaction_setup_recovery(struct tdb_context *tdb,
 }
 
 /*
-  commit the current transaction
+  prepare to commit the current transaction
 */
-int tdb_transaction_commit(struct tdb_context *tdb)
+int tdb_transaction_prepare_commit(struct tdb_context *tdb)
 {      
        const struct tdb_methods *methods;
-       tdb_off_t magic_offset = 0;
-       uint32_t zero = 0;
        int i;
 
        if (tdb->transaction == NULL) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: no transaction\n"));
+               return -1;
+       }
+
+       if (tdb->transaction->prepared) {
+               tdb->ecode = TDB_ERR_EINVAL;
+               tdb_transaction_cancel(tdb);
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction already prepared\n"));
                return -1;
        }
 
        if (tdb->transaction->transaction_error) {
                tdb->ecode = TDB_ERR_IO;
                tdb_transaction_cancel(tdb);
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: transaction error pending\n"));
                return -1;
        }
 
 
        if (tdb->transaction->nesting != 0) {
-               tdb->transaction->nesting--;
                return 0;
        }               
 
        /* check for a null transaction */
        if (tdb->transaction->blocks == NULL) {
-               tdb_transaction_cancel(tdb);
                return 0;
        }
 
@@ -865,14 +901,14 @@ int tdb_transaction_commit(struct tdb_context *tdb)
           nested their locks properly, so fail the transaction */
        if (tdb->num_locks || tdb->global_lock.count) {
                tdb->ecode = TDB_ERR_LOCK;
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: locks pending on commit\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: locks pending on commit\n"));
                tdb_transaction_cancel(tdb);
                return -1;
        }
 
        /* upgrade the main transaction lock region to a write lock */
        if (tdb_brlock_upgrade(tdb, FREELIST_TOP, 0) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_start: failed to upgrade hash locks\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to upgrade hash locks\n"));
                tdb->ecode = TDB_ERR_LOCK;
                tdb_transaction_cancel(tdb);
                return -1;
@@ -881,7 +917,7 @@ int tdb_transaction_commit(struct tdb_context *tdb)
        /* get the global lock - this prevents new users attaching to the database
           during the commit */
        if (tdb_brlock(tdb, GLOBAL_LOCK, F_WRLCK, F_SETLKW, 0, 1) == -1) {
-               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: failed to get global lock\n"));
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_prepare_commit: failed to get global lock\n"));
                tdb->ecode = TDB_ERR_LOCK;
                tdb_transaction_cancel(tdb);
                return -1;
@@ -889,21 +925,23 @@ int tdb_transaction_commit(struct tdb_context *tdb)
 
        if (!(tdb->flags & TDB_NOSYNC)) {
                /* write the recovery data to the end of the file */
-               if (transaction_setup_recovery(tdb, &magic_offset) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to setup recovery data\n"));
+               if (transaction_setup_recovery(tdb, &tdb->transaction->magic_offset) == -1) {
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: failed to setup recovery data\n"));
                        tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
                        tdb_transaction_cancel(tdb);
                        return -1;
                }
        }
 
+       tdb->transaction->prepared = true;
+
        /* expand the file to the new size if needed */
        if (tdb->map_size != tdb->transaction->old_map_size) {
                if (methods->tdb_expand_file(tdb, tdb->transaction->old_map_size, 
                                             tdb->map_size - 
                                             tdb->transaction->old_map_size) == -1) {
                        tdb->ecode = TDB_ERR_IO;
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: expansion failed\n"));
+                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_prepare_commit: expansion failed\n"));
                        tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
                        tdb_transaction_cancel(tdb);
                        return -1;
@@ -912,6 +950,51 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                methods->tdb_oob(tdb, tdb->map_size + 1, 1);
        }
 
+       /* Keep the global lock until the actual commit */
+
+       return 0;
+}
+
+/*
+  commit the current transaction
+*/
+int tdb_transaction_commit(struct tdb_context *tdb)
+{      
+       const struct tdb_methods *methods;
+       int i;
+
+       if (tdb->transaction == NULL) {
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: no transaction\n"));
+               return -1;
+       }
+
+       if (tdb->transaction->transaction_error) {
+               tdb->ecode = TDB_ERR_IO;
+               tdb_transaction_cancel(tdb);
+               TDB_LOG((tdb, TDB_DEBUG_ERROR, "tdb_transaction_commit: transaction error pending\n"));
+               return -1;
+       }
+
+
+       if (tdb->transaction->nesting != 0) {
+               tdb->transaction->nesting--;
+               return 0;
+       }
+
+       /* check for a null transaction */
+       if (tdb->transaction->blocks == NULL) {
+               tdb_transaction_cancel(tdb);
+               return 0;
+       }
+
+       if (!tdb->transaction->prepared) {
+               int ret = tdb_transaction_prepare_commit(tdb);
+               if (ret)
+                       return ret;
+       }
+
+       methods = tdb->transaction->io_methods;
+
        /* perform all the writes */
        for (i=0;i<tdb->transaction->num_blocks;i++) {
                tdb_off_t offset;
@@ -953,17 +1036,6 @@ int tdb_transaction_commit(struct tdb_context *tdb)
                if (transaction_sync(tdb, 0, tdb->map_size) == -1) {
                        return -1;
                }
-
-               /* remove the recovery marker */
-               if (methods->tdb_write(tdb, magic_offset, &zero, 4) == -1) {
-                       TDB_LOG((tdb, TDB_DEBUG_FATAL, "tdb_transaction_commit: failed to remove recovery magic\n"));
-                       return -1;
-               }
-
-               /* ensure the recovery marker has been removed on disk */
-               if (transaction_sync(tdb, magic_offset, 4) == -1) {
-                       return -1;
-               }
        }
 
        tdb_brlock(tdb, GLOBAL_LOCK, F_UNLCK, F_SETLKW, 0, 1);
index 2feaa6f5f556359268430820b46cfc8704223c3a..c42a970721cadc4309a6c86d2d9df3351579348b 100644 (file)
@@ -2,7 +2,7 @@ AC_PREREQ(2.50)
 AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
 AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
 AC_DEFUN([SMB_ENABLE], [echo -n ""])
-AC_INIT(tdb, 1.1.3)
+AC_INIT(tdb, 1.1.4)
 AC_CONFIG_SRCDIR([common/tdb.c])
 AC_CONFIG_HEADER(include/config.h)
 AC_LIBREPLACE_ALL_CHECKS
index 63fcf5e049b13ef01fc3cae78c7326be332287a8..454e4ba032b81275219bca255e20405f23ad1cea 100644 (file)
@@ -236,3 +236,11 @@ int tdb_transaction_commit(TDB_CONTEXT *tdb)
    commit a current transaction, updating the database and releasing
    the transaction locks.
 
+----------------------------------------------------------------------
+int tdb_transaction_prepare_commit(TDB_CONTEXT *tdb)
+
+   prepare to commit a current transaction, for two-phase commits.
+   Once prepared for commit, the only allowed calls are
+   tdb_transaction_commit() or tdb_transaction_cancel(). Preparing
+   allocates disk space for the pending updates, so a subsequent
+   commit should succeed (barring any hardware failures).
index 94b5e366b90cd28002ca4c21e405a0f2197b5ffb..22496f56f01d69fc981282221382bb15c46b825f 100644 (file)
@@ -129,6 +129,7 @@ int tdb_fd(struct tdb_context *tdb);
 tdb_log_func tdb_log_fn(struct tdb_context *tdb);
 void *tdb_get_logging_private(struct tdb_context *tdb);
 int tdb_transaction_start(struct tdb_context *tdb);
+int tdb_transaction_prepare_commit(struct tdb_context *tdb);
 int tdb_transaction_commit(struct tdb_context *tdb);
 int tdb_transaction_cancel(struct tdb_context *tdb);
 int tdb_transaction_recover(struct tdb_context *tdb);
index 9265cf07aa27976f36c54801758e2f6862e2b613..0c9bbd613d8b35a470cbf987540a8737eec0c977 100644 (file)
@@ -18,6 +18,7 @@
 #define STORE_PROB 4
 #define APPEND_PROB 6
 #define TRANSACTION_PROB 10
+#define TRANSACTION_PREPARE_PROB 2
 #define LOCKSTORE_PROB 5
 #define TRAVERSE_PROB 20
 #define TRAVERSE_READ_PROB 20
@@ -109,6 +110,11 @@ static void addrec_db(void)
                goto next;
        }
        if (in_transaction && random() % TRANSACTION_PROB == 0) {
+               if (random() % TRANSACTION_PREPARE_PROB == 0) {
+                       if (tdb_transaction_prepare_commit(db) != 0) {
+                               fatal("tdb_transaction_prepare_commit failed");
+                       }
+               }
                if (tdb_transaction_commit(db) != 0) {
                        fatal("tdb_transaction_commit failed");
                }
index 1cf8d9ca4a45d1b73fe750e053b872e977fb7748..0850bf5a7f29d0cf637dbb7da16ca583085ae108 100644 (file)
@@ -788,6 +788,7 @@ if test x$enable_cups != xno; then
                        x"$ac_cv_header_cups_language_h" = xyes; then
                        AC_DEFINE(HAVE_CUPS,1,[Whether we have CUPS])
                        samba_cv_HAVE_CUPS=yes
+                       AC_CHECK_LIB_EXT(cups, PRINT_LIBS, httpConnectEncrypt)
                else
                        AC_MSG_WARN([cups-config around but cups-devel not installed])
                        CFLAGS=$ac_save_CFLAGS
index 77be0aba09008d892033e01b21431d2f91c4df52..2e76764e018532617c5c9b0861d840ce837ffcda 100644 (file)
@@ -4125,6 +4125,7 @@ const char **lp_admin_users(int );
 const char **lp_svcctl_list(void);
 char *lp_cups_options(int );
 char *lp_cups_server(void);
+int lp_cups_encrypt(void);
 char *lp_iprint_server(void);
 int lp_cups_connection_timeout(void);
 const char *lp_ctdbd_socket(void);
index 66fb8bf1bc603f0c98da1983caf2472b36bb3afc..8da1f6348fb4a11b6fa6ace86057468ff950b3c1 100644 (file)
 #include "includes.h"
 #include "printing.h"
 
+#ifdef HAVE_HTTPCONNECTENCRYPT
+#include <cups/http.h>
+#endif
+
 bool bLoaded = False;
 
 extern enum protocol_types Protocol;
@@ -257,6 +261,7 @@ struct global {
        int ldap_debug_threshold;
        int iAclCompat;
        char *szCupsServer;
+       int CupsEncrypt;
        char *szIPrintServer;
        char *ctdbdSocket;
        char **szClusterAddresses;
@@ -774,6 +779,8 @@ static const struct enum_list enum_case[] = {
        {-1, NULL}
 };
 
+
+
 static const struct enum_list enum_bool_auto[] = {
        {False, "No"},
        {False, "False"},
@@ -2628,6 +2635,16 @@ static struct parm_struct parm_table[] = {
                .flags          = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
        },
        {
+               .label          = "cups encrypt",
+               .type           = P_ENUM,
+               .p_class        = P_GLOBAL,
+               .ptr            = &Globals.CupsEncrypt,
+               .special        = NULL,
+               .enum_list      = enum_bool_auto,
+               .flags          = FLAG_ADVANCED | FLAG_PRINT | FLAG_GLOBAL,
+       },
+       {
+
                .label          = "cups connection timeout",
                .type           = P_INTEGER,
                .p_class        = P_GLOBAL,
@@ -5471,6 +5488,23 @@ FN_LOCAL_LIST(lp_admin_users, szAdminUsers)
 FN_GLOBAL_LIST(lp_svcctl_list, &Globals.szServicesList)
 FN_LOCAL_STRING(lp_cups_options, szCupsOptions)
 FN_GLOBAL_STRING(lp_cups_server, &Globals.szCupsServer)
+int lp_cups_encrypt(void)
+{
+#ifdef HAVE_HTTPCONNECTENCRYPT
+       switch (Globals.CupsEncrypt) {
+               case Auto:
+                       Globals.CupsEncrypt = HTTP_ENCRYPT_REQUIRED;
+                       break;
+               case True:
+                       Globals.CupsEncrypt = HTTP_ENCRYPT_ALWAYS;
+                       break;
+               case False:
+                       Globals.CupsEncrypt = HTTP_ENCRYPT_NEVER;
+                       break;
+       }
+#endif
+       return Globals.CupsEncrypt;
+}
 FN_GLOBAL_STRING(lp_iprint_server, &Globals.szIPrintServer)
 FN_GLOBAL_INTEGER(lp_cups_connection_timeout, &Globals.cups_connection_timeout)
 FN_GLOBAL_CONST_STRING(lp_ctdbd_socket, &Globals.ctdbdSocket)
index 8e792a944a3b3283c8c8d8eae043f78f07de6140..7edfb5edbeb61cc49288286ce3b6c0075823e162 100644 (file)
@@ -93,7 +93,12 @@ static http_t *cups_connect(TALLOC_CTX *frame)
                 alarm(timeout);
         }
 
+#ifdef HAVE_HTTPCONNECTENCRYPT
+       http = httpConnectEncrypt(server, port, lp_cups_encrypt());
+#else
        http = httpConnect(server, port);
+#endif
+
 
        CatchSignal(SIGALRM, SIGNAL_CAST SIG_IGN);
         alarm(0);
index 555718bd83a02f2760365e3c83984003fc25326e..5ae715130335d4a5117740c6450c11cce722c14c 100644 (file)
@@ -325,8 +325,10 @@ uint32 dos_mode_msdfs(connection_struct *conn, const char *path,SMB_STRUCT_STAT
                } else {
                        p = path;
                }
-               
-               if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+
+               /* Only . and .. are not hidden. */
+               if (p[0] == '.' && !((p[1] == '\0') ||
+                               (p[1] == '.' && p[2] == '\0'))) {
                        result |= aHIDDEN;
                }
        }
@@ -484,8 +486,10 @@ uint32 dos_mode(connection_struct *conn, const char *path,SMB_STRUCT_STAT *sbuf)
                } else {
                        p = path;
                }
-               
-               if (p[0] == '.' && p[1] != '.' && p[1] != 0) {
+
+               /* Only . and .. are not hidden. */
+               if (p[0] == '.' && !((p[1] == '\0') ||
+                               (p[1] == '.' && p[2] == '\0'))) {
                        result |= aHIDDEN;
                }
        }
index 71a1b8e9427d288a99933eb4e023d137a44770bc..3231f7ab0fc9265cfd293fc9fb3b63588852bcd8 100644 (file)
@@ -73,11 +73,14 @@ static struct partition_context *partition_init_ctx(struct ldb_module *module, s
        return ac;
 }
 
-#define PARTITION_FIND_OP(module, op) do { \
-       struct ldb_context *ldbctx = module->ldb; \
+#define PARTITION_FIND_OP_NOERROR(module, op) do { \
         while (module && module->ops->op == NULL) module = module->next; \
+} while (0)
+
+#define PARTITION_FIND_OP(module, op) do { \
+       PARTITION_FIND_OP_NOERROR(module, op); \
         if (module == NULL) { \
-                ldb_asprintf_errstring(ldbctx, \
+                ldb_asprintf_errstring(module->ldb, \
                        "Unable to find backend operation for " #op ); \
                 return LDB_ERR_OPERATIONS_ERROR; \
         } \
@@ -654,7 +657,7 @@ static int partition_start_trans(struct ldb_module *module)
 /* end a transaction */
 static int partition_end_trans(struct ldb_module *module)
 {
-       int i, ret;
+       int i, ret, final_ret;
        struct partition_private_data *data = talloc_get_type(module->private_data, 
                                                              struct partition_private_data);
        ret = ldb_next_end_trans(module);
@@ -662,28 +665,60 @@ static int partition_end_trans(struct ldb_module *module)
                return ret;
        }
 
+       /* if the backend has a prepare_commit op then use that, to ensure
+          that all partitions are committed safely together */
+       for (i=0; data && data->partitions && data->partitions[i]; i++) {
+               struct ldb_module *next_end = data->partitions[i]->module;
+               struct ldb_module *next_prepare = data->partitions[i]->module;
+               struct ldb_module *next_del = data->partitions[i]->module;
+
+               PARTITION_FIND_OP_NOERROR(next_prepare, prepare_commit);
+               if (next_prepare == NULL) {
+                       continue;
+               }
+
+               PARTITION_FIND_OP(next_end, end_transaction);
+               PARTITION_FIND_OP(next_del, del_transaction);
+
+               if (next_end != next_prepare || next_del != next_end) {
+                       ldb_asprintf_errstring(module->ldb, "ERROR: Mismatch between prepare and commit ops in ldb module");
+                       return LDB_ERR_OPERATIONS_ERROR;
+               }
+               
+               ret = next_prepare->ops->prepare_commit(next_prepare);
+               if (ret != LDB_SUCCESS) {
+                       /* if one fails, cancel all but this one */
+                       int j;
+                       for (j=0; data->partitions[j]; j++) {
+                               if (j == i) continue;
+                               next_del = data->partitions[j]->module;
+                               PARTITION_FIND_OP(next_del, del_transaction);
+                               next_del->ops->del_transaction(next_del);
+                       }
+                       ldb_next_del_trans(module);
+                       return ret;
+               }
+       }
+
        /* Look at base DN */
        /* Figure out which partition it is under */
        /* Skip the lot if 'data' isn't here yet (initialistion) */
+       final_ret = LDB_SUCCESS;
+
        for (i=0; data && data->partitions && data->partitions[i]; i++) {
                struct ldb_module *next = data->partitions[i]->module;
                PARTITION_FIND_OP(next, end_transaction);
 
                ret = next->ops->end_transaction(next);
                if (ret != LDB_SUCCESS) {
-                       /* Back it out, if it fails on one */
-                       for (i--; i >= 0; i--) {
-                               next = data->partitions[i]->module;
-                               PARTITION_FIND_OP(next, del_transaction);
-
-                               next->ops->del_transaction(next);
-                       }
-                       ldb_next_del_trans(module);
-                       return ret;
+                       /* this should only be happening if we had a serious 
+                          OS or hardware error */
+                       ldb_asprintf_errstring(module->ldb, "ERROR: partition commit error");
+                       final_ret = ret;
                }
        }
 
-       return LDB_SUCCESS;
+       return final_ret;
 }
 
 /* delete a transaction */
index d61b31afd4420644f5d55983e18c765d9df60ad8..b98cc885371cdd33d638c13c11ddceb18e0a9a78 100644 (file)
@@ -11,7 +11,7 @@ AC_DEFUN([SMB_MODULE_DEFAULT], [echo -n ""])
 AC_DEFUN([SMB_LIBRARY_ENABLE], [echo -n ""])
 AC_DEFUN([SMB_EXT_LIB], [echo -n ""])
 AC_DEFUN([SMB_ENABLE], [echo -n ""])
-AC_INIT(ldb, 0.9.3)
+AC_INIT(ldb, 0.9.4)
 AC_CONFIG_SRCDIR([common/ldb.c])
 
 AC_LIBREPLACE_ALL_CHECKS
index 8c2cab702fdf128dd72f6f41acb655dd5ee8b512..cdfc5ea2fbb0eac799ea10ce3cf65ac8f8751f67 100644 (file)
@@ -4,4 +4,4 @@ AC_SUBST(TDB_LIBS)
 
 AC_CHECK_HEADER(tdb.h,
    [AC_CHECK_LIB(tdb, tdb_open, [TDB_LIBS="-ltdb"]) ],
-   [PKG_CHECK_MODULES(TDB, tdb >= 1.1.0)])
+   [PKG_CHECK_MODULES(TDB, tdb >= 1.1.4)])
index 4e1019184d32471156dfb65ea5a0c0067723f506..e07fd43e27199ec89db2485190f4b3213ecda751 100644 (file)
@@ -52,6 +52,7 @@ struct ldb_module_ops {
        int (*request)(struct ldb_module *, struct ldb_request *); /* match any other operation */
        int (*extended)(struct ldb_module *, struct ldb_request *); /* extended operations */
        int (*start_transaction)(struct ldb_module *);
+       int (*prepare_commit)(struct ldb_module *);
        int (*end_transaction)(struct ldb_module *);
        int (*del_transaction)(struct ldb_module *);
        int (*sequence_number)(struct ldb_module *, struct ldb_request *);
index ff8c1f3baf16263665a62f1dd8ac1d8e0837a0b7..0589baf5d4aa44ef210ee3898b96efd23c7b1122 100644 (file)
@@ -66,7 +66,7 @@ build-python:: ldb.$(SHLIBEXT)
 
 pyldb.o: $(ldbdir)/pyldb.c
        $(CC) $(PICFLAG) -c $(ldbdir)/pyldb.c $(CFLAGS) `$(PYTHON_CONFIG) --cflags`
-       
+
 ldb.$(SHLIBEXT): pyldb.o
        $(SHLD) $(SHLD_FLAGS) -o ldb.$(SHLIBEXT) pyldb.o $(LIB_FLAGS) `$(PYTHON_CONFIG) --ldflags`
 
index 9df62be93631baad29a71c60aea97ad2d75a2761..0f84b67afaa673c9dcd42400e32da0ddefeebbd1 100644 (file)
@@ -857,18 +857,46 @@ static int ltdb_start_trans(struct ldb_module *module)
        return LDB_SUCCESS;
 }
 
-static int ltdb_end_trans(struct ldb_module *module)
+static int ltdb_prepare_commit(struct ldb_module *module)
 {
        void *data = ldb_module_get_private(module);
        struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
 
-       ltdb->in_transaction--;
+       if (ltdb->in_transaction != 1) {
+               return LDB_SUCCESS;
+       }
 
        if (ltdb_index_transaction_commit(module) != 0) {
                tdb_transaction_cancel(ltdb->tdb);
+               ltdb->in_transaction--;
+               return ltdb_err_map(tdb_error(ltdb->tdb));
+       }
+
+       if (tdb_transaction_prepare_commit(ltdb->tdb) != 0) {
+               ltdb->in_transaction--;
                return ltdb_err_map(tdb_error(ltdb->tdb));
        }
 
+       ltdb->prepared_commit = true;
+
+       return LDB_SUCCESS;
+}
+
+static int ltdb_end_trans(struct ldb_module *module)
+{
+       void *data = ldb_module_get_private(module);
+       struct ltdb_private *ltdb = talloc_get_type(data, struct ltdb_private);
+
+       if (!ltdb->prepared_commit) {
+               int ret = ltdb_prepare_commit(module);
+               if (ret != LDB_SUCCESS) {
+                       return ret;
+               }
+       }
+
+       ltdb->in_transaction--;
+       ltdb->prepared_commit = false;
+
        if (tdb_transaction_commit(ltdb->tdb) != 0) {
                return ltdb_err_map(tdb_error(ltdb->tdb));
        }
@@ -1209,6 +1237,7 @@ static const struct ldb_module_ops ltdb_ops = {
        .extended          = ltdb_handle_request,
        .start_transaction = ltdb_start_trans,
        .end_transaction   = ltdb_end_trans,
+       .prepare_commit    = ltdb_prepare_commit,
        .del_transaction   = ltdb_del_trans,
 };
 
index 5a1c8fee2d7482948754bcc5e264c914e8da2d79..370cd0729b589c17ce105339cb0a1a989747826a 100644 (file)
@@ -30,6 +30,7 @@ struct ltdb_private {
 
        bool check_base;
        struct ltdb_idxptr *idxptr;
+       bool prepared_commit;
 };
 
 /*
index 1dd3501b992f09d1ac7538776b800b636689a0ec..0469fb827a5561f08054655afe8aeb4d1d5d857a 100644 (file)
@@ -1,6 +1,6 @@
 # Minimum and exact required versions for various libraries 
 # if we use the ones installed in the system.
-define(TDB_MIN_VERSION,1.1.3)
+define(TDB_MIN_VERSION,1.1.4)
 define(TALLOC_MIN_VERSION,1.3.0)
-define(LDB_REQUIRED_VERSION,0.9.3)
+define(LDB_REQUIRED_VERSION,0.9.4)
 define(TEVENT_REQUIRED_VERSION,0.9.5)