[SCM] Samba Shared Repository - branch master updated

Andrew Bartlett abartlet at samba.org
Wed May 22 05:59:02 UTC 2019


The branch, master has been updated
       via  a666a99e4dc ldb: ldbdump key and pack format version comments
       via  365838311b1 ldb: ldb_key_value_test fix
       via  64cdd0383f9 ldb: removing unnecessary module pointer
       via  bea24253f08 ldb: Release ldb 2.0.2
       via  8c0724fa10b ldb: pack function for new pack format
       via  38feff07312 ldb: unpack function for new pack format
       via  5bf6f0ae327 ldb: replacing length increments with constants in pack
       via  df1f8832047 ldb: push and pull macros for pack format
       via  474e5552322 ldb: baseinfo pack format check on init
      from  3e6661fd73b s4 librpc rpc pyrpc: Fix flapping dcerpc.bare tests

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit a666a99e4dc594bc153cd26b24cddd547c1cc750
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Mon May 20 16:19:51 2019 +1200

    ldb: ldbdump key and pack format version comments
    
    For testing we need to know the actual KV level key of records and each
    record's pack format version. This patch makes ldbdump add comments with
    that info. We will parse it out in python tests.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>
    
    Autobuild-User(master): Andrew Bartlett <abartlet at samba.org>
    Autobuild-Date(master): Wed May 22 05:58:17 UTC 2019 on sn-devel-184

commit 365838311b139b8163cc8f41b4cf2058809ae437
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Fri May 17 13:27:20 2019 +1200

    ldb: ldb_key_value_test fix
    
    In future commits we'll be adding more logging to LDB, which breaks the
    ldb_key_value_test suite. By removing the debug handler, a bug
    involving an expired debug_string variable being written to is avoided.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 64cdd0383f9083d84d38dd19168b013906ca9cf8
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Thu May 16 10:53:38 2019 +1200

    ldb: removing unnecessary module pointer
    
    We want to reuse the reindex context struct for repacking, but it has an
    unnecessary module pointer on it. Turns out the existing code doesn't
    need it either, so this patch deletes the pointer.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit bea24253f08d6aa6534d7743c7af0a5202446154
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Tue May 21 12:34:38 2019 +1200

    ldb: Release ldb 2.0.2
    
     * Checking pack format is version 1 and erroring if not (will change soon)
     * Pack format routines for unpack and pack version 2 (but not used)
     * Test fixes for issues caused by upcoming repack functionality for upgrade
     * Making ldbdump print out pack format info and keys so we have low level visibility for testing in python
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 8c0724fa10bc32980e5378114e0611b049924f74
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Fri May 10 18:10:55 2019 +1200

    ldb: pack function for new pack format
    
    Pack function for new pack format with values separated from other data
    so that while unpacking, the value section (which is probably large)
    doesn't have to be loaded into cache/memory.
    The new format is disabled for now.
    Two tests are added that operate on a detailed binary breakdown of the
    new format.
    
    NOTE: Configure with --abi-check-disable to build this commit. This
    patch is part of a set of LDB ABI changes, and the version update is
    done on the last commit.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 38feff073120ea87c100c05d8c9c3f6f771e5029
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Wed May 1 13:36:36 2019 +1200

    ldb: unpack function for new pack format
    
    Unpack function for new pack format with values separated from other
    data so that while unpacking, the value section (which is probably large)
    doesn't have to be loaded into cache/memory.
    Additionally, width of length field can now vary per-element to save space.
    The old unpack routine is still present and is called if the old pack
    format version number is found.
    LDB torture suite is modified to run relevant tests on both old and new
    pack format.
    
    NOTE: Configure with --abi-check-disable to build this commit. This
    patch is part of a set of LDB ABI changes, and the version update is
    done on the last commit.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 5bf6f0ae3271cb1a24416523f1132b09d998adf3
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Tue May 21 15:18:10 2019 +1200

    ldb: replacing length increments with constants in pack
    
    Since we're about to introduce a new packing format, it's a good time to
    improve our code style and change some magic numbers into explicit
    constants.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit df1f883204722a947c52497aaa79d75444a24b63
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Fri May 17 16:34:52 2019 +1200

    ldb: push and pull macros for pack format
    
    Replacing push and pull functions (which may cause issues with Undefined
    Sanitizer) with Andreas Schneider's excellent macros which are a work in
    progress and not yet merged into master. Once his work is upstream, I'll
    rebase and change this code to import his headers.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

commit 474e55523224430781ed22aa2d0c8a474306e794
Author: Aaron Haslett <aaronhaslett at catalyst.net.nz>
Date:   Fri May 10 18:10:51 2019 +1200

    ldb: baseinfo pack format check on init
    
    We will be adding a new packing format in forthcoming commits and there
    may be more versions in the future. We need to make sure the database
    contains records in a format we know how to read and write.
    Done by fetching the @BASEINFO record and reading the first 4
    bytes which contain the packing format version.
    
    NOTE: Configure with --abi-check-disable to build this commit. This
    patch is part of a set of LDB ABI changes, and the version update is
    done on the last commit.
    
    Signed-off-by: Aaron Haslett <aaronhaslett at catalyst.net.nz>
    Reviewed-by: Andrew Bartlett <abartlet at samba.org>
    Reviewed-by: Gary Lockyer <gary at catalyst.net.nz>

-----------------------------------------------------------------------

Summary of changes:
 lib/ldb/ABI/{ldb-2.0.1.sigs => ldb-2.0.2.sigs}     |   3 +-
 ...yldb-util-1.1.10.sigs => pyldb-util-2.0.2.sigs} |   0
 lib/ldb/common/ldb_pack.c                          | 845 +++++++++++++++++++--
 lib/ldb/include/ldb_module.h                       |  13 +-
 lib/ldb/ldb_key_value/ldb_kv.c                     |   5 +-
 lib/ldb/ldb_key_value/ldb_kv.h                     |   2 +-
 lib/ldb/ldb_key_value/ldb_kv_cache.c               |  37 +
 lib/ldb/ldb_key_value/ldb_kv_index.c               |   5 +-
 lib/ldb/ldb_tdb/ldb_tdb.c                          |   2 +-
 lib/ldb/tests/ldb_mod_op_test.c                    |   2 +
 lib/ldb/tools/ldbdump.c                            |  24 +
 lib/ldb/wscript                                    |   2 +-
 source4/torture/ldb/ldb.c                          | 431 ++++++++++-
 13 files changed, 1257 insertions(+), 114 deletions(-)
 copy lib/ldb/ABI/{ldb-2.0.1.sigs => ldb-2.0.2.sigs} (99%)
 copy lib/ldb/ABI/{pyldb-util-1.1.10.sigs => pyldb-util-2.0.2.sigs} (100%)


Changeset truncated at 500 lines:

diff --git a/lib/ldb/ABI/ldb-2.0.1.sigs b/lib/ldb/ABI/ldb-2.0.2.sigs
similarity index 99%
copy from lib/ldb/ABI/ldb-2.0.1.sigs
copy to lib/ldb/ABI/ldb-2.0.2.sigs
index f782d73afb1..5fc5560ee21 100644
--- a/lib/ldb/ABI/ldb-2.0.1.sigs
+++ b/lib/ldb/ABI/ldb-2.0.2.sigs
@@ -197,7 +197,7 @@ ldb_next_request: int (struct ldb_module *, struct ldb_request *)
 ldb_next_start_trans: int (struct ldb_module *)
 ldb_op_default_callback: int (struct ldb_request *, struct ldb_reply *)
 ldb_options_find: const char *(struct ldb_context *, const char **, const char *)
-ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *)
+ldb_pack_data: int (struct ldb_context *, const struct ldb_message *, struct ldb_val *, uint32_t)
 ldb_parse_control_from_string: struct ldb_control *(struct ldb_context *, TALLOC_CTX *, const char *)
 ldb_parse_control_strings: struct ldb_control **(struct ldb_context *, TALLOC_CTX *, const char **)
 ldb_parse_tree: struct ldb_parse_tree *(TALLOC_CTX *, const char *)
@@ -269,6 +269,7 @@ ldb_transaction_prepare_commit: int (struct ldb_context *)
 ldb_transaction_start: int (struct ldb_context *)
 ldb_unpack_data: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *)
 ldb_unpack_data_flags: int (struct ldb_context *, const struct ldb_val *, struct ldb_message *, unsigned int)
+ldb_unpack_get_format: int (const struct ldb_val *, uint32_t *)
 ldb_val_dup: struct ldb_val (TALLOC_CTX *, const struct ldb_val *)
 ldb_val_equal_exact: int (const struct ldb_val *, const struct ldb_val *)
 ldb_val_map_local: struct ldb_val (struct ldb_module *, void *, const struct ldb_map_attribute *, const struct ldb_val *)
diff --git a/lib/ldb/ABI/pyldb-util-1.1.10.sigs b/lib/ldb/ABI/pyldb-util-2.0.2.sigs
similarity index 100%
copy from lib/ldb/ABI/pyldb-util-1.1.10.sigs
copy to lib/ldb/ABI/pyldb-util-2.0.2.sigs
diff --git a/lib/ldb/common/ldb_pack.c b/lib/ldb/common/ldb_pack.c
index 5360a36cccc..9d87a10b9f1 100644
--- a/lib/ldb/common/ldb_pack.c
+++ b/lib/ldb/common/ldb_pack.c
@@ -33,27 +33,58 @@
 
 #include "ldb_private.h"
 
-/* change this if the data format ever changes */
-#define LDB_PACKING_FORMAT 0x26011967
-
-/* old packing formats */
-#define LDB_PACKING_FORMAT_NODN 0x26011966
-
-/* use a portable integer format */
-static void put_uint32(uint8_t *p, int ofs, unsigned int val)
-{
-	p += ofs;
-	p[0] = val&0xFF;
-	p[1] = (val>>8)  & 0xFF;
-	p[2] = (val>>16) & 0xFF;
-	p[3] = (val>>24) & 0xFF;
-}
-
-static unsigned int pull_uint32(uint8_t *p, int ofs)
-{
-	p += ofs;
-	return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
-}
+/*
+ * These macros are from byte_array.h via libssh
+ * TODO: This will be replaced with use of the byte_array.h header when it
+ * becomes available.
+ *
+ * Macros for handling integer types in byte arrays
+ *
+ * This file is originally from the libssh.org project
+ *
+ * Copyright (c) 2018 Andreas Schneider <asn at cryptomilk.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#define _DATA_BYTE_CONST(data, pos) \
+	((uint8_t)(((const uint8_t *)(data))[(pos)]))
+#define PULL_LE_U8(data, pos) \
+	(_DATA_BYTE_CONST(data, pos))
+#define PULL_LE_U16(data, pos) \
+	((uint16_t)PULL_LE_U8(data, pos) |\
+	((uint16_t)(PULL_LE_U8(data, (pos) + 1))) << 8)
+#define PULL_LE_U32(data, pos) \
+	((uint32_t)(PULL_LE_U16(data, pos) |\
+	((uint32_t)PULL_LE_U16(data, (pos) + 2)) << 16))
+
+#define _DATA_BYTE(data, pos) \
+	(((uint8_t *)(data))[(pos)])
+#define PUSH_LE_U8(data, pos, val) \
+	(_DATA_BYTE(data, pos) = ((uint8_t)(val)))
+#define PUSH_LE_U16(data, pos, val) \
+	(PUSH_LE_U8((data), (pos), (uint8_t)((uint16_t)(val) & 0xff)),\
+		    PUSH_LE_U8((data), (pos) + 1,\
+			       (uint8_t)((uint16_t)(val) >> 8)))
+#define PUSH_LE_U32(data, pos, val) \
+	(PUSH_LE_U16((data), (pos), (uint16_t)((uint32_t)(val) & 0xffff)),\
+	 PUSH_LE_U16((data), (pos) + 2, (uint16_t)((uint32_t)(val) >> 16)))
+
+#define U32_LEN 4
+#define U16_LEN 2
+#define U8_LEN 1
+#define NULL_PAD_BYTE_LEN 1
 
 static int attribute_storable_values(const struct ldb_message_element *el)
 {
@@ -64,17 +95,9 @@ static int attribute_storable_values(const struct ldb_message_element *el)
 	return el->num_values;
 }
 
-/*
-  pack a ldb message into a linear buffer in a ldb_val
-
-  note that this routine avoids saving elements with zero values,
-  as these are equivalent to having no element
-
-  caller frees the data buffer after use
-*/
-int ldb_pack_data(struct ldb_context *ldb,
-		  const struct ldb_message *message,
-		  struct ldb_val *data)
+static int ldb_pack_data_v1(struct ldb_context *ldb,
+			    const struct ldb_message *message,
+			    struct ldb_val *data)
 {
 	unsigned int i, j, real_elements=0;
 	size_t size, dn_len, attr_len, value_len;
@@ -89,9 +112,7 @@ int ldb_pack_data(struct ldb_context *ldb,
 	}
 
 	/* work out how big it needs to be */
-	size = 8;
-
-	size += 1;
+	size = U32_LEN * 2 + NULL_PAD_BYTE_LEN;
 
 	dn_len = strlen(dn);
 	if (size + dn_len < size) {
@@ -111,11 +132,11 @@ int ldb_pack_data(struct ldb_context *ldb,
 
 		real_elements++;
 
-		if (size + 5 < size) {
+		if (size + U32_LEN + NULL_PAD_BYTE_LEN < size) {
 			errno = ENOMEM;
 			return -1;
 		}
-		size += 5;
+		size += U32_LEN + NULL_PAD_BYTE_LEN;
 
 		attr_len = strlen(message->elements[i].name);
 		if (size + attr_len < size) {
@@ -125,11 +146,11 @@ int ldb_pack_data(struct ldb_context *ldb,
 		size += attr_len;
 
 		for (j=0;j<message->elements[i].num_values;j++) {
-			if (size + 5 < size) {
+			if (size + U32_LEN + NULL_PAD_BYTE_LEN < size) {
 				errno = ENOMEM;
 				return -1;
 			}
-			size += 5;
+			size += U32_LEN + NULL_PAD_BYTE_LEN;
 
 			value_len = message->elements[i].values[j].length;
 			if (size + value_len < size) {
@@ -149,31 +170,35 @@ int ldb_pack_data(struct ldb_context *ldb,
 	data->length = size;
 
 	p = data->data;
-	put_uint32(p, 0, LDB_PACKING_FORMAT);
-	put_uint32(p, 4, real_elements);
-	p += 8;
+	PUSH_LE_U32(p, 0, LDB_PACKING_FORMAT);
+	p += U32_LEN;
+	PUSH_LE_U32(p, 0, real_elements);
+	p += U32_LEN;
 
 	/* the dn needs to be packed so we can be case preserving
 	   while hashing on a case folded dn */
 	len = dn_len;
-	memcpy(p, dn, len+1);
-	p += len + 1;
+	memcpy(p, dn, len+NULL_PAD_BYTE_LEN);
+	p += len + NULL_PAD_BYTE_LEN;
 
 	for (i=0;i<message->num_elements;i++) {
 		if (attribute_storable_values(&message->elements[i]) == 0) {
 			continue;
 		}
 		len = strlen(message->elements[i].name);
-		memcpy(p, message->elements[i].name, len+1);
-		p += len + 1;
-		put_uint32(p, 0, message->elements[i].num_values);
-		p += 4;
+		memcpy(p, message->elements[i].name, len+NULL_PAD_BYTE_LEN);
+		p += len + NULL_PAD_BYTE_LEN;
+		PUSH_LE_U32(p, 0, message->elements[i].num_values);
+		p += U32_LEN;
 		for (j=0;j<message->elements[i].num_values;j++) {
-			put_uint32(p, 0, message->elements[i].values[j].length);
-			memcpy(p+4, message->elements[i].values[j].data,
+			PUSH_LE_U32(p, 0,
+				    message->elements[i].values[j].length);
+			p += U32_LEN;
+			memcpy(p, message->elements[i].values[j].data,
 			       message->elements[i].values[j].length);
-			p[4+message->elements[i].values[j].length] = 0;
-			p += 4 + message->elements[i].values[j].length + 1;
+			p[message->elements[i].values[j].length] = 0;
+			p += message->elements[i].values[j].length +
+				NULL_PAD_BYTE_LEN;
 		}
 	}
 
@@ -181,21 +206,343 @@ int ldb_pack_data(struct ldb_context *ldb,
 }
 
 /*
- * Unpack a ldb message from a linear buffer in ldb_val
+ * New pack version designed based on performance profiling of version 1.
+ * The approach is to separate value data from the rest of the record's data.
+ * This improves performance because value data is not needed during unpacking
+ * or filtering of the message's attribute list. During filtering we only copy
+ * attributes which are present in the attribute list, however at the parse
+ * stage we need to point to all attributes as they may be referenced in the
+ * search expression.
+ * With this new format, we don't lose time loading data (eg via
+ * talloc_memdup()) that is never needed (for the vast majority of attributes
+ * are are never found in either the search expression or attribute list).
+ * Additional changes include adding a canonicalized DN (for later
+ * optimizations) and variable width length fields for faster unpacking.
+ * The pack and unpack performance improvement is tested in the torture
+ * test torture_ldb_pack_format_perf.
  *
- * Providing a list of attributes to this function allows selective unpacking.
- * Giving a NULL list (or a list_size of 0) unpacks all the attributes.
+ * Layout:
+ *
+ * Version (4 bytes)
+ * Number of Elements (4 bytes)
+ * DN length (4 bytes)
+ * DN with null terminator (DN length + 1 bytes)
+ * Canonicalized DN length (4 bytes)
+ * Canonicalized DN with null terminator (Canonicalized DN length + 1 bytes)
+ * Number of bytes from here to value data section (4 bytes)
+ * # For each element:
+ * 	Element name length (4 bytes)
+ * 	Element name with null terminator (Element name length + 1 bytes)
+ * 	Number of values (4 bytes)
+ * 	Width of value lengths
+ * 	# For each value:
+ * 		Value data length (#bytes given by width field above)
+ * # For each element:
+ * 	# For each value:
+ *	 	Value data (#bytes given by corresponding length above)
  */
-int ldb_unpack_data_flags(struct ldb_context *ldb,
-			  const struct ldb_val *data,
-			  struct ldb_message *message,
-			  unsigned int flags)
+static int ldb_pack_data_v2(struct ldb_context *ldb,
+			    const struct ldb_message *message,
+			    struct ldb_val *data)
+{
+	unsigned int i, j, real_elements=0;
+	size_t size, dn_len, dn_canon_len, attr_len, value_len;
+	const char *dn, *dn_canon;
+	uint8_t *p, *q;
+	size_t len;
+	size_t max_val_len;
+	uint8_t val_len_width;
+
+	/*
+	 * First half of this function will calculate required size for
+	 * packed data. Initial size is 20 = 5 * 4.  5 fixed fields are:
+	 * version, num elements, dn len, canon dn len, attr section len
+	 */
+	size = U32_LEN * 5;
+
+	/*
+	 * Get linearized and canonicalized form of the DN and add the lengths
+	 * of each to size, plus 1 for null terminator.
+	 */
+	dn = ldb_dn_get_linearized(message->dn);
+	if (dn == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+
+	dn_len = strlen(dn) + NULL_PAD_BYTE_LEN;
+	if (size + dn_len < size) {
+		errno = ENOMEM;
+		return -1;
+	}
+	size += dn_len;
+
+	if (ldb_dn_is_special(message->dn)) {
+		dn_canon_len = NULL_PAD_BYTE_LEN;
+		dn_canon = discard_const_p(char, "\0");
+	} else {
+		dn_canon = ldb_dn_canonical_string(message->dn, message->dn);
+		if (dn_canon == NULL) {
+			errno = ENOMEM;
+			return -1;
+		}
+
+		dn_canon_len = strlen(dn_canon) + NULL_PAD_BYTE_LEN;
+		if (size + dn_canon_len < size) {
+			errno = ENOMEM;
+			return -1;
+		}
+	}
+	size += dn_canon_len;
+
+	/* Add the size required by each element */
+	for (i=0;i<message->num_elements;i++) {
+		if (attribute_storable_values(&message->elements[i]) == 0) {
+			continue;
+		}
+
+		real_elements++;
+
+		/*
+		 * Add length of element name + 9 for:
+		 * 1 for null terminator
+		 * 4 for element name length field
+		 * 4 for number of values field
+		 */
+		attr_len = strlen(message->elements[i].name);
+		if (size + attr_len + U32_LEN * 2 + NULL_PAD_BYTE_LEN < size) {
+			errno = ENOMEM;
+			return -1;
+		}
+		size += attr_len + U32_LEN * 2 + NULL_PAD_BYTE_LEN;
+
+		/*
+		 * Find the max value length, so we can calculate the width
+		 * required for the value length fields.
+		 */
+		max_val_len = 0;
+		for (j=0;j<message->elements[i].num_values;j++) {
+			value_len = message->elements[i].values[j].length;
+			if (value_len > max_val_len) {
+				max_val_len = value_len;
+			}
+
+			if (size + value_len + NULL_PAD_BYTE_LEN < size) {
+				errno = ENOMEM;
+				return -1;
+			}
+			size += value_len + NULL_PAD_BYTE_LEN;
+		}
+
+		if (max_val_len <= UCHAR_MAX) {
+			val_len_width = U8_LEN;
+		} else if (max_val_len <= USHRT_MAX) {
+			val_len_width = U16_LEN;
+		} else if (max_val_len <= UINT_MAX) {
+		        val_len_width = U32_LEN;
+		} else {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		/* Total size required for val lengths (re-using variable) */
+		max_val_len = (val_len_width*message->elements[i].num_values);
+
+		/* Add one for storing the width */
+		max_val_len += U8_LEN;
+		if (size + max_val_len < size) {
+			errno = ENOMEM;
+			return -1;
+		}
+		size += max_val_len;
+	}
+
+	/* Allocate */
+	data->data = talloc_array(ldb, uint8_t, size);
+	if (!data->data) {
+		errno = ENOMEM;
+		return -1;
+	}
+	data->length = size;
+
+	/* Packing format version and number of element */
+	p = data->data;
+	PUSH_LE_U32(p, 0, LDB_PACKING_FORMAT_V2);
+	p += U32_LEN;
+	PUSH_LE_U32(p, 0, real_elements);
+	p += U32_LEN;
+
+	/* Pack DN and Canonicalized DN */
+	PUSH_LE_U32(p, 0, dn_len-NULL_PAD_BYTE_LEN);
+	p += U32_LEN;
+	memcpy(p, dn, dn_len);
+	p += dn_len;
+
+	PUSH_LE_U32(p, 0, dn_canon_len-NULL_PAD_BYTE_LEN);
+	p += U32_LEN;
+	memcpy(p, dn_canon, dn_canon_len);
+	p += dn_canon_len;
+
+	/*
+	 * Save pointer at this point and leave a U32_LEN gap for
+	 * storing the size of the attribute names and value lengths
+	 * section
+	 */
+	q = p;
+	p += U32_LEN;
+
+	for (i=0;i<message->num_elements;i++) {
+		if (attribute_storable_values(&message->elements[i]) == 0) {
+			continue;
+		}
+
+		/* Length of el name */
+		len = strlen(message->elements[i].name);
+		PUSH_LE_U32(p, 0, len);
+		p += U32_LEN;
+
+		/*
+		 * Even though we have the element name's length, put a null
+		 * terminator at the end so if any code uses the name
+		 * directly, it'll be safe to do things requiring null
+		 * termination like strlen
+		 */
+		memcpy(p, message->elements[i].name, len+NULL_PAD_BYTE_LEN);
+		p += len + NULL_PAD_BYTE_LEN;
+		/* Num values */
+		PUSH_LE_U32(p, 0, message->elements[i].num_values);
+		p += U32_LEN;
+
+		/*
+		 * Calculate value length width again. It's faster to
+		 * calculate it again than do the array management to
+		 * store the result during size calculation.
+		 */
+		max_val_len = 0;
+		for (j=0;j<message->elements[i].num_values;j++) {
+			value_len = message->elements[i].values[j].length;
+			if (value_len > max_val_len) {
+				max_val_len = value_len;
+			}
+		}
+
+		if (max_val_len <= UCHAR_MAX) {
+			val_len_width = U8_LEN;
+		} else if (max_val_len <= USHRT_MAX) {
+			val_len_width = U16_LEN;
+		} else if (max_val_len <= UINT_MAX) {
+		        val_len_width = U32_LEN;
+		} else {
+			errno = EMSGSIZE;
+			return -1;
+		}
+
+		/* Pack the width */
+		*p = val_len_width & 0xFF;
+		p += U8_LEN;
+
+		/*
+		 * Pack each value's length using the minimum number of bytes
+		 * required, which we just calculated. We repeat the loop
+		 * for each case here so the compiler can inline code.
+		 */
+		if (val_len_width == U8_LEN) {
+			for (j=0;j<message->elements[i].num_values;j++) {
+				PUSH_LE_U8(p, 0,
+					message->elements[i].values[j].length);
+				p += U8_LEN;
+			}
+		} else if (val_len_width == U16_LEN) {
+			for (j=0;j<message->elements[i].num_values;j++) {
+				PUSH_LE_U16(p, 0,
+					message->elements[i].values[j].length);
+				p += U16_LEN;
+			}
+		} else if (val_len_width == U32_LEN) {
+			for (j=0;j<message->elements[i].num_values;j++) {
+				PUSH_LE_U32(p, 0,
+					message->elements[i].values[j].length);
+				p += U32_LEN;
+			}
+		}
+	}
+
+	/*
+	 * We've finished packing the attr names and value lengths
+	 * section, so store the size in the U32_LEN gap we left
+	 * earlier
+	 */
+	PUSH_LE_U32(q, 0, p-q);
+


-- 
Samba Shared Repository



More information about the samba-cvs mailing list