diff options
Diffstat (limited to 'libglusterfs/src/dict.c')
-rw-r--r-- | libglusterfs/src/dict.c | 2243 |
1 files changed, 2243 insertions, 0 deletions
diff --git a/libglusterfs/src/dict.c b/libglusterfs/src/dict.c new file mode 100644 index 00000000000..eb181f191c3 --- /dev/null +++ b/libglusterfs/src/dict.c @@ -0,0 +1,2243 @@ +/* + Copyright (c) 2006, 2007, 2008 Z RESEARCH, Inc. <http://www.zresearch.com> + This file is part of GlusterFS. + + GlusterFS is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3 of the License, + or (at your option) any later version. + + GlusterFS 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see + <http://www.gnu.org/licenses/>. +*/ + +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <inttypes.h> + +#ifndef _CONFIG_H +#define _CONFIG_H +#include "config.h" +#endif + +#include "common-utils.h" +#include "dict.h" +#include "hashfn.h" +#include "logging.h" +#include "compat.h" +#include "byte-order.h" + +data_pair_t * +get_new_data_pair () +{ + data_pair_t *data_pair_ptr = NULL; + + data_pair_ptr = (data_pair_t *) CALLOC (1, sizeof (data_pair_t)); + ERR_ABORT (data_pair_ptr); + + return data_pair_ptr; +} + +data_t * +get_new_data () +{ + data_t *data = NULL; + + data = (data_t *) CALLOC (1, sizeof (data_t)); + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "calloc () returned NULL"); + return NULL; + } + + LOCK_INIT (&data->lock); + return data; +} + +dict_t * +get_new_dict_full (int size_hint) +{ + dict_t *dict = CALLOC (1, sizeof (dict_t)); + + if (!dict) { + gf_log ("dict", GF_LOG_CRITICAL, + "calloc () returned NULL"); + return NULL; + } + + dict->hash_size = size_hint; + dict->members = CALLOC (size_hint, sizeof (data_pair_t *)); + + if (!dict->members) { + gf_log ("dict", GF_LOG_CRITICAL, + "calloc () returned NULL"); + return NULL; + } + + LOCK_INIT (&dict->lock); + + return dict; +} + +dict_t * +get_new_dict (void) +{ + return get_new_dict_full (1); +} + +dict_t * +dict_new (void) +{ + dict_t *dict = NULL; + + dict = get_new_dict_full(1); + + if (dict) + dict_ref (dict); + + return dict; +} + + +int32_t +is_data_equal (data_t *one, + data_t *two) +{ + if (!one || !two || !one->data || !two->data) + return 1; + + if (one == two) + return 1; + + if (one->len != two->len) + return 0; + + if (one->data == two->data) + return 1; + + if (memcmp (one->data, two->data, one->len) == 0) + return 1; + + return 0; +} + +void +data_destroy (data_t *data) +{ + if (data) { + LOCK_DESTROY (&data->lock); + + if (!data->is_static) { + if (data->data) + FREE (data->data); + if (data->vec) + FREE (data->vec); + } + + data->len = 0xbabababa; + if (!data->is_const) + FREE (data); + } +} + +data_t * +data_copy (data_t *old) +{ + if (!old) { + gf_log ("dict", GF_LOG_CRITICAL, + "@old is NULL"); + return NULL; + } + + data_t *newdata = (data_t *) CALLOC (1, sizeof (*newdata)); + + if (!newdata) { + gf_log ("dict", GF_LOG_CRITICAL, + "@old is NULL"); + return NULL; + } + + if (old) { + newdata->len = old->len; + if (old->data) + newdata->data = memdup (old->data, old->len); + if (old->vec) + newdata->vec = memdup (old->vec, old->len * (sizeof (void *) + + sizeof (size_t))); + if (!old->data && !old->vec) { + gf_log ("dict", GF_LOG_CRITICAL, + "@newdata->data || @newdata->vec got NULL from CALLOC()"); + return NULL; + } + } + + return newdata; +} + +static data_pair_t * +_dict_lookup (dict_t *this, char *key) +{ + if (!this || !key) { + gf_log ("dict", GF_LOG_CRITICAL, + "@this=%p @key=%p", this, key); + return NULL; + } + + int hashval = SuperFastHash (key, strlen (key)) % this->hash_size; + data_pair_t *pair; + + for (pair = this->members[hashval]; pair != NULL; pair = pair->hash_next) { + if (pair->key && !strcmp (pair->key, key)) + return pair; + } + + return NULL; +} + + +static int32_t +_dict_set (dict_t *this, + char *key, + data_t *value) +{ + int hashval; + data_pair_t *pair; + char key_free = 0; + int tmp = 0; + + if (!key) { + asprintf (&key, "ref:%p", value); + key_free = 1; + } + + tmp = SuperFastHash (key, strlen (key)); + hashval = (tmp % this->hash_size); + pair = _dict_lookup (this, key); + + if (pair) { + data_t *unref_data = pair->value; + pair->value = data_ref (value); + data_unref (unref_data); + if (key_free) + FREE (key); + /* Indicates duplicate key */ + return 0; + } + pair = (data_pair_t *) CALLOC (1, sizeof (*pair)); + if (!pair) { + gf_log ("dict", GF_LOG_CRITICAL, + "@pair - NULL returned by CALLOC"); + return -1; + } + + pair->key = (char *) CALLOC (1, strlen (key) + 1); + if (!pair->key) { + gf_log ("dict", GF_LOG_CRITICAL, + "@pair->key - NULL returned by CALLOC"); + return -1; + } + + strcpy (pair->key, key); + pair->value = data_ref (value); + + pair->hash_next = this->members[hashval]; + this->members[hashval] = pair; + + pair->next = this->members_list; + pair->prev = NULL; + if (this->members_list) + this->members_list->prev = pair; + this->members_list = pair; + this->count++; + + if (key_free) + FREE (key); + return 0; +} + +int32_t +dict_set (dict_t *this, + char *key, + data_t *value) +{ + int32_t ret; + + if (!this || !value) { + gf_log ("dict", GF_LOG_CRITICAL, + "@this=%p @value=%p", this, value); + return -1; + } + + LOCK (&this->lock); + + ret = _dict_set (this, key, value); + + UNLOCK (&this->lock); + + return ret; +} + + +data_t * +dict_get (dict_t *this, + char *key) +{ + data_pair_t *pair; + + if (!this || !key) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p @key=%p", this, key); + return NULL; + } + + LOCK (&this->lock); + + pair = _dict_lookup (this, key); + + UNLOCK (&this->lock); + + if (pair) + return pair->value; + + return NULL; +} + +void +dict_del (dict_t *this, + char *key) +{ + if (!this || !key) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p @key=%p", this, key); + return; + } + + LOCK (&this->lock); + + int hashval = SuperFastHash (key, strlen (key)) % this->hash_size; + data_pair_t *pair = this->members[hashval]; + data_pair_t *prev = NULL; + + while (pair) { + if (strcmp (pair->key, key) == 0) { + if (prev) + prev->hash_next = pair->hash_next; + else + this->members[hashval] = pair->hash_next; + + data_unref (pair->value); + + if (pair->prev) + pair->prev->next = pair->next; + else + this->members_list = pair->next; + + if (pair->next) + pair->next->prev = pair->prev; + + FREE (pair->key); + FREE (pair); + this->count--; + break; + } + + prev = pair; + pair = pair->hash_next; + } + + UNLOCK (&this->lock); + + return; +} + +void +dict_destroy (dict_t *this) +{ + if (!this) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p", this); + return; + } + + data_pair_t *pair = this->members_list; + data_pair_t *prev = this->members_list; + + LOCK_DESTROY (&this->lock); + + while (prev) { + pair = pair->next; + data_unref (prev->value); + FREE (prev->key); + FREE (prev); + prev = pair; + } + + FREE (this->members); + + if (this->extra_free) + FREE (this->extra_free); + + if (!this->is_static) + FREE (this); + + return; +} + +void +dict_unref (dict_t *this) +{ + int32_t ref; + + if (!this) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p", this); + return; + } + + LOCK (&this->lock); + + this->refcount--; + ref = this->refcount; + + UNLOCK (&this->lock); + + if (!ref) + dict_destroy (this); +} + +dict_t * +dict_ref (dict_t *this) +{ + if (!this) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p", this); + return NULL; + } + + LOCK (&this->lock); + + this->refcount++; + + UNLOCK (&this->lock); + + return this; +} + +void +data_unref (data_t *this) +{ + int32_t ref; + + if (!this) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p", this); + return; + } + + LOCK (&this->lock); + + this->refcount--; + ref = this->refcount; + + UNLOCK (&this->lock); + + if (!ref) + data_destroy (this); +} + +data_t * +data_ref (data_t *this) +{ + if (!this) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p", this); + return NULL; + } + + LOCK (&this->lock); + + this->refcount++; + + UNLOCK (&this->lock); + + return this; +} + +/* + Serialization format: + ---- + Count:8 + Key_len:8:Value_len:8 + Key + Value + . + . + . +*/ + +int32_t +dict_serialized_length_old (dict_t *this) +{ + + if (!this) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p", this); + return -1; + } + + int32_t len = 9; /* count + \n */ + int32_t count = this->count; + data_pair_t *pair = this->members_list; + + while (count) { + len += 18; + len += strlen (pair->key) + 1; + if (pair->value->vec) { + int i; + for (i=0; i<pair->value->len; i++) { + len += pair->value->vec[i].iov_len; + } + } else { + len += pair->value->len; + } + pair = pair->next; + count--; + } + + return len; +} + +int32_t +dict_serialize_old (dict_t *this, char *buf) +{ + if (!this || !buf) { + gf_log ("dict", GF_LOG_DEBUG, + "@this=%p @buf=%p", this, buf); + return -1; + } + + data_pair_t *pair = this->members_list; + int32_t count = this->count; + uint64_t dcount = this->count; + + // FIXME: magic numbers + + sprintf (buf, "%08"PRIx64"\n", dcount); + buf += 9; + while (count) { + uint64_t keylen = strlen (pair->key) + 1; + uint64_t vallen = pair->value->len; + + sprintf (buf, "%08"PRIx64":%08"PRIx64"\n", keylen, vallen); + buf += 18; + memcpy (buf, pair->key, keylen); + buf += keylen; + memcpy (buf, pair->value->data, pair->value->len); + buf += pair->value->len; + pair = pair->next; + count--; + } + return (0); +} + + +dict_t * +dict_unserialize_old (char *buf, int32_t size, dict_t **fill) +{ + int32_t ret = 0; + int32_t cnt = 0; + + if (!buf || fill == NULL || !*fill) { + gf_log ("dict", GF_LOG_ERROR, + "@buf=%p @fill=%p @*fill=%p", buf, fill, *fill); + return NULL; + } + + uint64_t count; + ret = sscanf (buf, "%"SCNx64"\n", &count); + (*fill)->count = 0; + + if (!ret){ + gf_log ("dict", + GF_LOG_ERROR, + "sscanf on buf failed"); + goto err; + } + buf += 9; + + if (count == 0) { + gf_log ("dict", + GF_LOG_ERROR, + "count == 0"); + goto err; + } + + for (cnt = 0; cnt < count; cnt++) { + data_t *value = NULL; + char *key = NULL; + uint64_t key_len, value_len; + + ret = sscanf (buf, "%"SCNx64":%"SCNx64"\n", &key_len, &value_len); + if (ret != 2) { + gf_log ("dict", + GF_LOG_ERROR, + "sscanf for key_len and value_len failed"); + goto err; + } + buf += 18; + + key = buf; + buf += key_len; + + value = get_new_data (); + value->len = value_len; + value->data = buf; + value->is_static = 1; + buf += value_len; + + dict_set (*fill, key, value); + } + + goto ret; + +err: + FREE (*fill); + *fill = NULL; + +ret: + return *fill; +} + + +int32_t +dict_iovec_len (dict_t *this) +{ + if (!this) { + gf_log ("dict", GF_LOG_CRITICAL, + "@this=%p", this); + return -1; + } + + int32_t len = 0; + data_pair_t *pair = this->members_list; + + len++; /* initial header */ + while (pair) { + len++; /* pair header */ + len++; /* key */ + + if (pair->value->vec) + len += pair->value->len; + else + len++; + pair = pair->next; + } + + return len; +} + +int32_t +dict_to_iovec (dict_t *this, + struct iovec *vec, + int32_t count) +{ + if (!this || !vec) { + gf_log ("dict", GF_LOG_CRITICAL, + "@this=%p @vec=%p", this, vec); + return -1; + } + + int32_t i = 0; + data_pair_t *pair = this->members_list; + + vec[0].iov_len = 9; + if (vec[0].iov_base) + sprintf (vec[0].iov_base, + "%08"PRIx64"\n", + (int64_t)this->count); + i++; + + while (pair) { + int64_t keylen = strlen (pair->key) + 1; + int64_t vallen = 0; + + if (pair->value->vec) { + int i; + + for (i=0; i<pair->value->len; i++) { + vallen += pair->value->vec[i].iov_len; + } + } else { + vallen = pair->value->len; + } + + vec[i].iov_len = 18; + if (vec[i].iov_base) + sprintf (vec[i].iov_base, + "%08"PRIx64":%08"PRIx64"\n", + keylen, + vallen); + i++; + + vec[i].iov_len = keylen; + vec[i].iov_base = pair->key; + i++; + + if (pair->value->vec) { + int k; + + for (k=0; k<pair->value->len; k++) { + vec[i].iov_len = pair->value->vec[k].iov_len; + vec[i].iov_base = pair->value->vec[k].iov_base; + i++; + } + } else { + vec[i].iov_len = pair->value->len; + vec[i].iov_base = pair->value->data; + i++; + } + + pair = pair->next; + } + + return 0; +} + +data_t * +int_to_data (int64_t value) +{ + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + + asprintf (&data->data, "%"PRId64, value); + data->len = strlen (data->data) + 1; + + return data; +} + +data_t * +data_from_int64 (int64_t value) +{ + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + asprintf (&data->data, "%"PRId64, value); + data->len = strlen (data->data) + 1; + + return data; +} + +data_t * +data_from_int32 (int32_t value) +{ + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + asprintf (&data->data, "%"PRId32, value); + data->len = strlen (data->data) + 1; + + return data; +} + +data_t * +data_from_int16 (int16_t value) +{ + + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + asprintf (&data->data, "%"PRId16, value); + data->len = strlen (data->data) + 1; + + return data; +} + +data_t * +data_from_int8 (int8_t value) +{ + + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + asprintf (&data->data, "%d", value); + data->len = strlen (data->data) + 1; + + return data; +} + +data_t * +data_from_uint64 (uint64_t value) +{ + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + asprintf (&data->data, "%"PRIu64, value); + data->len = strlen (data->data) + 1; + + return data; +} + + +data_t * +data_from_uint32 (uint32_t value) +{ + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + asprintf (&data->data, "%"PRIu32, value); + data->len = strlen (data->data) + 1; + + return data; +} + + +data_t * +data_from_uint16 (uint16_t value) +{ + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + asprintf (&data->data, "%"PRIu16, value); + data->len = strlen (data->data) + 1; + + return data; +} + + +data_t * +data_from_ptr (void *value) +{ + if (!value) { + gf_log ("dict", GF_LOG_CRITICAL, + "@value=%p", value); + return NULL; + } + + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + + data->data = value; + return data; +} + +data_t * +data_from_static_ptr (void *value) +{ +/* + this is valid to set 0 as value.. + + if (!value) { + gf_log ("dict", GF_LOG_CRITICAL, + "@value=%p", value); + return NULL; + } +*/ + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + + data->is_static = 1; + data->data = value; + + return data; +} + +data_t * +str_to_data (char *value) +{ + if (!value) { + gf_log ("dict", GF_LOG_CRITICAL, + "@value=%p", value); + return NULL; + } + data_t *data = get_new_data (); + + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data - NULL returned by CALLOC"); + return NULL; + } + data->len = strlen (value) + 1; + + data->data = value; + data->is_static = 1; + + return data; +} + +data_t * +data_from_dynstr (char *value) +{ + if (!value) { + gf_log ("dict", GF_LOG_CRITICAL, + "@value=%p", value); + return NULL; + } + + data_t *data = get_new_data (); + + data->len = strlen (value) + 1; + data->data = value; + + return data; +} + +data_t * +data_from_dynptr (void *value, int32_t len) +{ + data_t *data = get_new_data (); + + data->len = len; + data->data = value; + + return data; +} + +data_t * +bin_to_data (void *value, int32_t len) +{ + if (!value) { + gf_log ("dict", GF_LOG_CRITICAL, + "@value=%p", value); + return NULL; + } + + data_t *data = get_new_data (); + + data->is_static = 1; + data->len = len; + data->data = value; + + return data; +} + +int64_t +data_to_int64 (data_t *data) +{ + if (!data) + return -1; + + char *str = alloca (data->len + 1); + ERR_ABORT (str); + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + return (int64_t) strtoull (str, NULL, 0); +} + +int32_t +data_to_int32 (data_t *data) +{ + if (!data) + return -1; + + char *str = alloca (data->len + 1); + ERR_ABORT (str); + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + return strtoul (str, NULL, 0); +} + +int16_t +data_to_int16 (data_t *data) +{ + if (!data) + return -1; + + char *str = alloca (data->len + 1); + ERR_ABORT (str); + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + return strtol (str, NULL, 0); +} + + +int8_t +data_to_int8 (data_t *data) +{ + if (!data) + return -1; + + char *str = alloca (data->len + 1); + ERR_ABORT (str); + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + return (int8_t)strtol (str, NULL, 0); +} + + +uint64_t +data_to_uint64 (data_t *data) +{ + if (!data) + return -1; + char *str = alloca (data->len + 1); + ERR_ABORT (str); + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + return strtoll (str, NULL, 0); +} + +uint32_t +data_to_uint32 (data_t *data) +{ + if (!data) + return -1; + + char *str = alloca (data->len + 1); + ERR_ABORT (str); + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + return strtol (str, NULL, 0); +} + +uint16_t +data_to_uint16 (data_t *data) +{ + if (!data) + return -1; + + char *str = alloca (data->len + 1); + ERR_ABORT (str); + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + return strtol (str, NULL, 0); +} + +char * +data_to_str (data_t *data) +{ + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data=%p", data); + return NULL; + } + return data->data; +} + +void * +data_to_ptr (data_t *data) +{ + if (!data) { + return NULL; + } + return data->data; +} + +void * +data_to_bin (data_t *data) +{ + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data=%p", data); + return NULL; + } + return data->data; +} + +void +dict_foreach (dict_t *dict, + void (*fn)(dict_t *this, + char *key, + data_t *value, + void *data), + void *data) +{ + if (!data) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data=%p", data); + return; + } + + data_pair_t *pairs = dict->members_list; + + while (pairs) { + fn (dict, pairs->key, pairs->value, data); + pairs = pairs->next; + } +} + + +static void +_copy (dict_t *unused, + char *key, + data_t *value, + void *newdict) +{ + dict_set ((dict_t *)newdict, key, (value)); +} + + +dict_t * +dict_copy (dict_t *dict, + dict_t *new) +{ + if (!dict) { + gf_log ("dict", GF_LOG_CRITICAL, + "@data=%p", dict); + return NULL; + } + + if (!new) + new = get_new_dict_full (dict->hash_size); + + dict_foreach (dict, _copy, new); + + return new; +} + +dict_t * +dict_copy_with_ref (dict_t *dict, + dict_t *new) +{ + dict_t *local_new = NULL; + + GF_VALIDATE_OR_GOTO("dict", dict, fail); + + if (new == NULL) { + local_new = dict_new (); + GF_VALIDATE_OR_GOTO("dict", local_new, fail); + new = local_new; + } + + dict_foreach (dict, _copy, new); +fail: + return new; +} + +/* + * !!!!!!! CLEANED UP CODE !!!!!!! + */ + +/** + * Common cleaned up interface: + * + * Return value: 0 success + * -val error, val = errno + */ + + +static int +dict_get_with_ref (dict_t *this, char *key, data_t **data) +{ + data_pair_t * pair = NULL; + int ret = -ENOENT; + + if (!this || !key || !data) { + ret = -EINVAL; + goto err; + } + + LOCK (&this->lock); + { + pair = _dict_lookup (this, key); + } + UNLOCK (&this->lock); + + if (pair) { + ret = 0; + *data = data_ref (pair->value); + } + +err: + return ret; +} + +static int +_data_to_ptr (data_t *data, void **val) +{ + int ret = 0; + + if (!data) { + ret = -EINVAL; + goto err; + } + + *val = data->data; +err: + return ret; +} + + +static int +_data_to_int8 (data_t *data, int8_t *val) +{ + int ret = 0; + char * str = NULL; + + if (!data || !val) { + ret = -EINVAL; + goto err; + } + + str = alloca (data->len + 1); + if (!str) { + ret = -ENOMEM; + goto err; + } + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + errno = 0; + *val = strtol (str, NULL, 0); + if (errno != 0) + ret = -errno; + +err: + return ret; +} + +static int +_data_to_int16 (data_t *data, int16_t *val) +{ + int ret = 0; + char * str = NULL; + + if (!data || !val) { + ret = -EINVAL; + goto err; + } + + str = alloca (data->len + 1); + if (!str) { + ret = -ENOMEM; + goto err; + } + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + errno = 0; + *val = strtol (str, NULL, 0); + if (errno != 0) + ret = -errno; + +err: + return ret; +} + +static int +_data_to_int32 (data_t *data, int32_t *val) +{ + int ret = 0; + char * str = NULL; + + if (!data || !val) { + ret = -EINVAL; + goto err; + } + + str = alloca (data->len + 1); + if (!str) { + ret = -ENOMEM; + goto err; + } + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + errno = 0; + *val = strtol (str, NULL, 0); + if (errno != 0) + ret = -errno; + +err: + return ret; +} + +static int +_data_to_int64 (data_t *data, int64_t *val) +{ + int ret = 0; + char * str = NULL; + + if (!data || !val) { + ret = -EINVAL; + goto err; + } + + str = alloca (data->len + 1); + if (!str) { + ret = -ENOMEM; + goto err; + } + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + errno = 0; + *val = strtoll (str, NULL, 0); + if (errno != 0) + ret = -errno; + +err: + return ret; +} + +static int +_data_to_uint16 (data_t *data, uint16_t *val) +{ + int ret = 0; + char * str = NULL; + + if (!data || !val) { + ret = -EINVAL; + goto err; + } + + str = alloca (data->len + 1); + if (!str) { + ret = -ENOMEM; + goto err; + } + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + errno = 0; + *val = strtoul (str, NULL, 0); + if (errno != 0) + ret = -errno; + +err: + return ret; +} + +static int +_data_to_uint32 (data_t *data, uint32_t *val) +{ + int ret = 0; + char * str = NULL; + + if (!data || !val) { + ret = -EINVAL; + goto err; + } + + str = alloca (data->len + 1); + if (!str) { + ret = -ENOMEM; + goto err; + } + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + errno = 0; + *val = strtoul (str, NULL, 0); + if (errno != 0) + ret = -errno; + +err: + return ret; +} + +static int +_data_to_uint64 (data_t *data, uint64_t *val) +{ + int ret = 0; + char * str = NULL; + + if (!data || !val) { + ret = -EINVAL; + goto err; + } + + str = alloca (data->len + 1); + if (!str) { + ret = -ENOMEM; + goto err; + } + memcpy (str, data->data, data->len); + str[data->len] = '\0'; + + errno = 0; + *val = strtoull (str, NULL, 0); + if (errno != 0) + ret = -errno; + +err: + return ret; +} + +int +dict_get_int8 (dict_t *this, char *key, int8_t *val) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_int8 (data, val); + +err: + if (data) + data_unref (data); + return ret; +} + + +int +dict_set_int8 (dict_t *this, char *key, int8_t val) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_int8 (val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_get_int16 (dict_t *this, char *key, int16_t *val) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_int16 (data, val); + +err: + if (data) + data_unref (data); + return ret; +} + + +int +dict_set_int16 (dict_t *this, char *key, int16_t val) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_int16 (val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_get_int32 (dict_t *this, char *key, int32_t *val) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_int32 (data, val); + +err: + if (data) + data_unref (data); + return ret; +} + + +int +dict_set_int32 (dict_t *this, char *key, int32_t val) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_int32 (val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_get_int64 (dict_t *this, char *key, int64_t *val) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_int64 (data, val); + +err: + if (data) + data_unref (data); + return ret; +} + + +int +dict_set_int64 (dict_t *this, char *key, int64_t val) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_int64 (val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_get_uint16 (dict_t *this, char *key, uint16_t *val) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_uint16 (data, val); + +err: + if (data) + data_unref (data); + return ret; +} + + +int +dict_set_uint16 (dict_t *this, char *key, uint16_t val) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_uint16 (val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_get_uint32 (dict_t *this, char *key, uint32_t *val) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_uint32 (data, val); + +err: + if (data) + data_unref (data); + return ret; +} + + +int +dict_set_uint32 (dict_t *this, char *key, uint32_t val) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_uint32 (val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_get_uint64 (dict_t *this, char *key, uint64_t *val) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !val) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_uint64 (data, val); + +err: + if (data) + data_unref (data); + return ret; +} + + +int +dict_set_uint64 (dict_t *this, char *key, uint64_t val) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_uint64 (val); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_set_static_ptr (dict_t *this, char *key, void *ptr) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_static_ptr (ptr); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_set_dynptr (dict_t *this, char *key, void *ptr, size_t len) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_dynptr (ptr, len); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_get_ptr (dict_t *this, char *key, void **ptr) +{ + data_t * data = NULL; + int ret = 0; + + if (!this || !key || !ptr) { + ret = -EINVAL; + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret != 0) { + goto err; + } + + ret = _data_to_ptr (data, ptr); + if (ret != 0) { + goto err; + } + +err: + if (data) + data_unref (data); + + return ret; +} + +int +dict_set_ptr (dict_t *this, char *key, void *ptr) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_ptr (ptr); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + + +int +dict_get_str (dict_t *this, char *key, char **str) +{ + data_t * data = NULL; + int ret = -EINVAL; + + if (!this || !key || !str) { + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret < 0) { + goto err; + } + + if (!data || !data->data) { + goto err; + } + *str = data->data; + +err: + if (data) + data_unref (data); + + return ret; +} + +int +dict_set_str (dict_t *this, char *key, char *str) +{ + data_t * data = NULL; + int ret = 0; + + data = str_to_data (str); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + +int +dict_set_dynstr (dict_t *this, char *key, char *str) +{ + data_t * data = NULL; + int ret = 0; + + data = data_from_dynstr (str); + if (!data) { + ret = -EINVAL; + goto err; + } + + ret = dict_set (this, key, data); + +err: + return ret; +} + + +int +dict_get_bin (dict_t *this, char *key, void **bin) +{ + data_t * data = NULL; + int ret = -EINVAL; + + if (!this || !key || !bin) { + goto err; + } + + ret = dict_get_with_ref (this, key, &data); + if (ret < 0) { + goto err; + } + + if (!data || !data->data) { + goto err; + } + *bin = data->data; + +err: + if (data) + data_unref (data); + + return ret; +} + + +int +dict_set_bin (dict_t *this, char *key, void *ptr, size_t size) +{ + data_t * data = NULL; + int ret = 0; + + if (!ptr || (size < 0)) { + ret = -EINVAL; + goto err; + } + + data = bin_to_data (ptr, size); + if (!data) { + ret = -EINVAL; + goto err; + } + + data->data = ptr; + data->len = size; + data->is_static = 0; + + ret = dict_set (this, key, data); + +err: + return ret; +} + + +int +dict_set_static_bin (dict_t *this, char *key, void *ptr, size_t size) +{ + data_t * data = NULL; + int ret = 0; + + if (!ptr || (size < 0)) { + ret = -EINVAL; + goto err; + } + + data = bin_to_data (ptr, size); + if (!data) { + ret = -EINVAL; + goto err; + } + + data->data = ptr; + data->len = size; + data->is_static = 1; + + ret = dict_set (this, key, data); + +err: + return ret; +} + +/** + * Serialization format: + * -------- -------- -------- ----------- ------------- + * | count | key len | val len | key \0| value + * ---------------------------------------- ------------- + * 4 4 4 <key len> <value len> + */ + +#define DICT_HDR_LEN 4 +#define DICT_DATA_HDR_KEY_LEN 4 +#define DICT_DATA_HDR_VAL_LEN 4 + +/** + * dict_serialized_length - return the length of serialized dict + * + * @this: dict to be serialized + * @return: success: len + * : failure: -errno + */ + +int +dict_serialized_length (dict_t *this) +{ + int ret = -EINVAL; + int count = 0; + int len = 0; + int i = 0; + data_pair_t * pair = NULL; + + if (!this) { + gf_log ("dict", GF_LOG_ERROR, "this is null!"); + goto out; + } + + len = DICT_HDR_LEN; + count = this->count; + + if (count < 0) { + gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); + goto out; + } + + pair = this->members_list; + + while (count) { + if (!pair) { + gf_log ("dict", GF_LOG_ERROR, + "less than count data pairs found!"); + goto out; + } + + len += DICT_DATA_HDR_KEY_LEN + DICT_DATA_HDR_VAL_LEN; + + if (!pair->key) { + gf_log ("dict", GF_LOG_ERROR, "pair->key is null!"); + goto out; + } + + len += strlen (pair->key) + 1 /* for '\0' */; + + if (!pair->value) { + gf_log ("dict", GF_LOG_ERROR, + "pair->value is null!"); + goto out; + } + + if (pair->value->vec) { + for (i = 0; i < pair->value->len; i++) { + if (pair->value->vec[i].iov_len < 0) { + gf_log ("dict", GF_LOG_ERROR, + "iov_len (%"GF_PRI_SIZET") < 0!", + pair->value->vec[i].iov_len); + goto out; + } + + len += pair->value->vec[i].iov_len; + } + } else { + if (pair->value->len < 0) { + gf_log ("dict", GF_LOG_ERROR, + "value->len (%d) < 0", + pair->value->len); + goto out; + } + + len += pair->value->len; + } + + pair = pair->next; + count--; + } + + ret = len; +out: + return ret; +} + +/** + * dict_serialize - serialize a dictionary into a buffer + * + * @this: dict to serialize + * @buf: buffer to serialize into. This must be + * atleast dict_serialized_length (this) large + * + * @return: success: 0 + * failure: -errno + */ + +int +dict_serialize (dict_t *this, char *buf) +{ + int ret = -1; + data_pair_t * pair = NULL; + int32_t count = 0; + int32_t keylen = 0; + int32_t vallen = 0; + + if (!this) { + gf_log ("dict", GF_LOG_ERROR, + "this is null!"); + goto out; + } + if (!buf) { + gf_log ("dict", GF_LOG_ERROR, + "buf is null!"); + goto out; + } + + count = this->count; + if (count < 0) { + gf_log ("dict", GF_LOG_ERROR, "count (%d) < 0!", count); + goto out; + } + + *(int32_t *) buf = hton32 (count); + buf += DICT_HDR_LEN; + pair = this->members_list; + + while (count) { + if (!pair) { + gf_log ("dict", GF_LOG_ERROR, + "less than count data pairs found!"); + goto out; + } + + if (!pair->key) { + gf_log ("dict", GF_LOG_ERROR, + "pair->key is null!"); + goto out; + } + + keylen = strlen (pair->key); + *(int32_t *) buf = hton32 (keylen); + buf += DICT_DATA_HDR_KEY_LEN; + + if (!pair->value) { + gf_log ("dict", GF_LOG_ERROR, + "pair->value is null!"); + goto out; + } + + vallen = pair->value->len; + *(int32_t *) buf = hton32 (vallen); + buf += DICT_DATA_HDR_VAL_LEN; + + memcpy (buf, pair->key, keylen); + buf += keylen; + *buf++ = '\0'; + + if (!pair->value->data) { + gf_log ("dict", GF_LOG_ERROR, + "pair->value->data is null!"); + goto out; + } + memcpy (buf, pair->value->data, vallen); + buf += vallen; + + pair = pair->next; + count--; + } + + ret = 0; +out: + return ret; +} + + +/** + * dict_unserialize - unserialize a buffer into a dict + * + * @buf: buf containing serialized dict + * @size: size of the @buf + * @fill: dict to fill in + * + * @return: success: 0 + * failure: -errno + */ + +int32_t +dict_unserialize (char *orig_buf, int32_t size, dict_t **fill) +{ + char *buf = NULL; + int ret = -1; + int32_t count = 0; + int i = 0; + + data_t * value = NULL; + char * key = NULL; + int32_t keylen = 0; + int32_t vallen = 0; + + + buf = orig_buf; + + if (!buf) { + gf_log ("dict", GF_LOG_ERROR, + "buf is null!"); + goto out; + } + + if (size == 0) { + gf_log ("dict", GF_LOG_ERROR, + "size is 0!"); + goto out; + } + + if (!fill) { + gf_log ("dict", GF_LOG_ERROR, + "fill is null!"); + goto out; + } + + if (!*fill) { + gf_log ("dict", GF_LOG_ERROR, + "*fill is null!"); + goto out; + } + + if ((buf + DICT_HDR_LEN) > (orig_buf + size)) { + gf_log ("dict", GF_LOG_ERROR, + "undersized buffer passsed"); + goto out; + } + + count = ntoh32 (*(int32_t *) buf); + buf += DICT_HDR_LEN; + + if (count < 0) { + gf_log ("dict", GF_LOG_ERROR, + "count (%d) <= 0", count); + goto out; + } + + /* count will be set by the dict_set's below */ + (*fill)->count = 0; + + for (i = 0; i < count; i++) { + if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) { + gf_log ("dict", GF_LOG_ERROR, + "undersized buffer passsed"); + goto out; + } + keylen = ntoh32 (*(int32_t *) buf); + buf += DICT_DATA_HDR_KEY_LEN; + + if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) { + gf_log ("dict", GF_LOG_ERROR, + "undersized buffer passsed"); + goto out; + } + vallen = ntoh32 (*(int32_t *) buf); + buf += DICT_DATA_HDR_VAL_LEN; + + if ((buf + keylen) > (orig_buf + size)) { + gf_log ("dict", GF_LOG_ERROR, + "undersized buffer passsed"); + goto out; + } + key = buf; + buf += keylen + 1; /* for '\0' */ + + if ((buf + vallen) > (orig_buf + size)) { + gf_log ("dict", GF_LOG_ERROR, + "undersized buffer passsed"); + goto out; + } + value = get_new_data (); + value->len = vallen; + value->data = buf; + value->is_static = 1; + buf += vallen; + + dict_set (*fill, key, value); + } + + ret = 0; +out: + return ret; +} + |