diff options
Diffstat (limited to 'source4/lib/ldb/ldb_tdb/ldb_pack.c')
-rw-r--r-- | source4/lib/ldb/ldb_tdb/ldb_pack.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/source4/lib/ldb/ldb_tdb/ldb_pack.c b/source4/lib/ldb/ldb_tdb/ldb_pack.c new file mode 100644 index 0000000000..b0c825e8e2 --- /dev/null +++ b/source4/lib/ldb/ldb_tdb/ldb_pack.c @@ -0,0 +1,174 @@ +/* + ldb database library + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the ldb + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + 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 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* + * Name: ldb + * + * Component: ldb pack/unpack + * + * Description: pack/unpack routines for ldb messages as key/value blobs + * + * Author: Andrew Tridgell + */ + +#include "includes.h" +#include "ldb_tdb/ldb_tdb.h" + +/* change this if the data format ever changes */ +#define LTDB_PACKING_FORMAT 0x26011966 + +/* + pack a ldb message into a linear buffer in a TDB_DATA + + caller frees the data buffer after use +*/ +int ltdb_pack_data(struct ldb_context *ctx, + const struct ldb_message *message, + struct TDB_DATA *data) +{ + int i; + size_t size; + char *p; + + /* work out how big it needs to be */ + size = 8; + + for (i=0;i<message->num_elements;i++) { + size += 1 + strlen(message->elements[i].name); + size += 4 + message->elements[i].value.length + 1; + } + + /* allocate it */ + data->dptr = malloc(size); + if (!data->dptr) { + errno = ENOMEM; + return -1; + } + data->dsize = size; + + p = data->dptr; + SIVAL(p, 0, LTDB_PACKING_FORMAT); + SIVAL(p, 4, message->num_elements); + p += 8; + + for (i=0;i<message->num_elements;i++) { + size_t len = strlen(message->elements[i].name); + memcpy(p, message->elements[i].name, len+1); + p += len + 1; + SIVAL(p, 0, message->elements[i].value.length); + memcpy(p+4, message->elements[i].value.data, + message->elements[i].value.length); + p[4+message->elements[i].value.length] = 0; + p += 4 + message->elements[i].value.length + 1; + } + + return 0; +} + + +/* + unpack a ldb message from a linear buffer in TDB_DATA + + note that this does not fill in the class and key elements + + caller frees. Memory for the elements[] array is malloced, + but the memory for the elements is re-used from the TDB_DATA + data. This means the caller only has to free the elements array +*/ +int ltdb_unpack_data(struct ldb_context *ctx, + const struct TDB_DATA *data, + struct ldb_message *message) +{ + char *p; + unsigned int remaining; + int i; + + message->elements = NULL; + + p = data->dptr; + if (data->dsize < 4) { + errno = EIO; + goto failed; + } + + if (IVAL(p, 0) != LTDB_PACKING_FORMAT) { + /* this is where we will cope with upgrading the + format if/when the format is ever changed */ + errno = EIO; + goto failed; + } + + message->num_elements = IVAL(p, 4); + p += 8; + + if (message->num_elements == 0) { + message->elements = NULL; + return 0; + } + + /* basic sanity check */ + remaining = data->dsize - 8; + + if (message->num_elements > remaining / 6) { + errno = EIO; + goto failed; + } + + message->elements = malloc_array_p(struct ldb_message_element, + message->num_elements); + + if (!message->elements) { + errno = ENOMEM; + goto failed; + } + + for (i=0;i<message->num_elements;i++) { + size_t len; + if (remaining < 6) { + errno = EIO; + goto failed; + } + len = strnlen(p, remaining-6); + message->elements[i].name = p; + remaining -= len + 1; + p += len + 1; + len = IVAL(p, 0); + if (len > remaining-5) { + errno = EIO; + goto failed; + } + message->elements[i].value.length = len; + message->elements[i].value.data = p+4; + remaining -= len+4+1; + p += len+4+1; + } + + return 0; + +failed: + if (message->elements) { + free(message->elements); + } + return -1; +} |