glusterfs
3383 строки · 77.1 Кб
1/*
2Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3This file is part of GlusterFS.
4
5This file is licensed to you under your choice of the GNU Lesser
6General Public License, version 3 or any later version (LGPLv3 or
7later), or the GNU General Public License, version 2 (GPLv2), in all
8cases as published by the Free Software Foundation.
9*/
10
11#include <unistd.h>12#include <string.h>13#include <stdlib.h>14#include <stdio.h>15#include <inttypes.h>16#include <limits.h>17#include <fnmatch.h>18
19#include "glusterfs/dict.h"20#include "glusterfs/compat.h"21#include "glusterfs/compat-errno.h"22#include "glusterfs/statedump.h"23#include "glusterfs/libglusterfs-messages.h"24
25struct dict_cmp {26dict_t *dict;27gf_boolean_t (*value_ignore)(char *k);28};29
30#define VALIDATE_DATA_AND_LOG(data, type, key, ret_val) \31do { \32if (!data || !data->data) { \33gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \34"data is NULL"); \35return ret_val; \36} \37/* Not of the asked type, or old version */ \38if ((data->data_type != type) && \39(data->data_type != GF_DATA_TYPE_STR_OLD)) { \40gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \41"key %s, %s type asked, has %s type", key, \42data_type_name[type], \43data_type_name[data->data_type]); \44} \45} while (0)46
47static data_t *48get_new_data(void)49{
50data_t *data = NULL;51
52if (global_ctx) {53data = mem_get(global_ctx->dict_data_pool);54} else {55data = mem_get(THIS->ctx->dict_data_pool);56}57
58if (!data)59return NULL;60
61GF_ATOMIC_INIT(data->refcount, 0);62data->is_static = _gf_false;63
64return data;65}
66
67static dict_t *68get_new_dict_full(void)69{
70dict_t *dict = mem_get0(THIS->ctx->dict_pool);71
72if (!dict) {73return NULL;74}75
76dict->totkvlen = 0;77LOCK_INIT(&dict->lock);78
79return dict;80}
81
82dict_t *83dict_new(void)84{
85dict_t *dict = get_new_dict_full();86
87if (dict)88dict_ref(dict);89
90return dict;91}
92
93int32_t
94is_data_equal(data_t *one, data_t *two)95{
96struct iatt *iatt1, *iatt2;97struct mdata_iatt *mdata_iatt1, *mdata_iatt2;98
99if (!one || !two || !one->data || !two->data) {100gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,101"input arguments are provided "102"with value data_t as NULL");103return -1;104}105
106if (one == two)107return 1;108
109if (one->data == two->data)110return 1;111
112if (one->data_type != two->data_type) {113return 0;114}115
116if (one->data_type == GF_DATA_TYPE_IATT) {117if ((one->len < sizeof(struct iatt)) ||118(two->len < sizeof(struct iatt))) {119return 0;120}121
122iatt1 = (struct iatt *)one->data;123iatt2 = (struct iatt *)two->data;124
125/* Two iatt structs are considered equal if main fields are126* equal, even if times differ.
127* TODO: maybe when ctime if fully operational we could
128* enforce time matching. */
129if (iatt1->ia_ino != iatt2->ia_ino) {130return 0;131}132if (iatt1->ia_type != iatt2->ia_type) {133return 0;134}135if ((iatt1->ia_type == IA_IFBLK) || (iatt1->ia_type == IA_IFCHR)) {136if (iatt1->ia_rdev != iatt2->ia_rdev) {137return 0;138}139}140if (gf_uuid_compare(iatt1->ia_gfid, iatt2->ia_gfid) != 0) {141return 0;142}143
144/* TODO: ia_uid, ia_gid, ia_prot and ia_size can be changed145* with some commands. Here we don't have enough
146* information to decide if they should match or not. */
147/*148if ((iatt1->ia_uid != iatt2->ia_uid) ||
149(iatt1->ia_gid != iatt2->ia_gid) ||
150(st_mode_from_ia(iatt1->ia_prot, iatt1->ia_type) !=
151st_mode_from_ia(iatt2->ia_prot,
152iatt2->ia_type))) { return 0;
153}
154if (iatt1->ia_type == IA_IFREG) {
155if (iatt1->ia_size != iatt2->ia_size) {
156return 0;
157}
158}
159*/
160return 1;161}162if (one->data_type == GF_DATA_TYPE_MDATA) {163if ((one->len < sizeof(struct mdata_iatt)) ||164(two->len < sizeof(struct mdata_iatt))) {165return 0;166}167mdata_iatt1 = (struct mdata_iatt *)one->data;168mdata_iatt2 = (struct mdata_iatt *)two->data;169
170if (mdata_iatt1->ia_atime != mdata_iatt2->ia_atime ||171mdata_iatt1->ia_mtime != mdata_iatt2->ia_mtime ||172mdata_iatt1->ia_ctime != mdata_iatt2->ia_ctime ||173mdata_iatt1->ia_atime_nsec != mdata_iatt2->ia_atime_nsec ||174mdata_iatt1->ia_mtime_nsec != mdata_iatt2->ia_mtime_nsec ||175mdata_iatt1->ia_ctime_nsec != mdata_iatt2->ia_ctime_nsec) {176return 0;177}178return 1;179}180
181if (one->len != two->len)182return 0;183
184if (memcmp(one->data, two->data, one->len) == 0)185return 1;186
187return 0;188}
189
190static int191key_value_cmp(dict_t *one, char *key1, data_t *value1, void *data)192{
193struct dict_cmp *cmp = data;194dict_t *two = cmp->dict;195data_t *value2 = dict_get(two, key1);196
197if (value2) {198if (cmp->value_ignore && cmp->value_ignore(key1))199return 0;200
201if (is_data_equal(value1, value2) == 1)202return 0;203}204
205if (value2 == NULL) {206gf_msg_debug(THIS->name, 0, "'%s' found only on one dict", key1);207} else {208gf_msg_debug(THIS->name, 0,209"'%s' is different in two dicts "210"(%u, %u)",211key1, value1->len, value2->len);212}213
214return -1;215}
216
217static inline gf_boolean_t218dict_match_everything(dict_t *d, char *k, data_t *v, void *data)219{
220return _gf_true;221}
222
223/* If both dicts are NULL then equal. If one of the dicts is NULL but the
224* other has only ignorable keys then also they are equal. If both dicts are
225* non-null then check if for each non-ignorable key, values are same or
226* not. value_ignore function is used to skip comparing values for the keys
227* which must be present in both the dictionaries but the value could be
228* different.
229*/
230gf_boolean_t
231are_dicts_equal(dict_t *one, dict_t *two,232gf_boolean_t (*match)(dict_t *d, char *k, data_t *v,233void *data),234void *match_data, gf_boolean_t (*value_ignore)(char *k))235{
236int num_matches1 = 0;237int num_matches2 = 0;238struct dict_cmp cmp = {0};239
240if (one == two)241return _gf_true;242
243if (!match)244match = dict_match_everything;245
246if ((one == NULL) || (two == NULL)) {247num_matches1 = dict_foreach_match(one ? one : two, match, NULL,248dict_null_foreach_fn, NULL);249goto done;250}251
252cmp.dict = two;253cmp.value_ignore = value_ignore;254num_matches1 = dict_foreach_match(one, match, match_data, key_value_cmp,255&cmp);256
257if (num_matches1 == -1)258return _gf_false;259
260if ((num_matches1 == one->count) && (one->count == two->count))261return _gf_true;262
263num_matches2 = dict_foreach_match(two, match, match_data,264dict_null_foreach_fn, NULL);265done:266/* If the number of matches is same in 'two' then for all the267* valid-keys that exist in 'one' the value matched and no extra valid
268* keys exist in 'two' alone. Otherwise there exists at least one extra
269* valid-key in 'two' which doesn't exist in 'one' */
270if (num_matches1 == num_matches2)271return _gf_true;272return _gf_false;273}
274
275static void276data_destroy(data_t *data)277{
278if (data) {279if (!data->is_static)280GF_FREE(data->data);281
282data->len = 0xbabababa;283mem_put(data);284}285}
286
287data_t *288data_copy(data_t *old)289{
290if (!old) {291gf_msg_callingfn("dict", GF_LOG_WARNING, 0, LG_MSG_NULL_PTR,292"old is NULL");293return NULL;294}295
296data_t *newdata = mem_get0(THIS->ctx->dict_data_pool);297if (!newdata) {298return NULL;299}300
301newdata->len = old->len;302if (old->data) {303newdata->data = gf_memdup(old->data, old->len);304if (!newdata->data)305goto err_out;306}307newdata->data_type = old->data_type;308
309return newdata;310
311err_out:312mem_put(newdata);313
314return NULL;315}
316
317/* Always need to be called under lock
318* Always this and key variables are not null -
319* checked by callers.
320*/
321static data_pair_t *322dict_lookup_common(const dict_t *this, const char *key)323{
324data_pair_t *pair;325
326for (pair = this->members_list; pair != NULL; pair = pair->next) {327if (!strcmp(pair->key, key))328return pair;329}330
331return NULL;332}
333
334int32_t
335dict_lookup(dict_t *this, char *key, data_t **data)336{
337if (!this || !key || !data) {338gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,339"!this || !key || "340"!data");341return -1;342}343
344data_pair_t *tmp = NULL;345
346LOCK(&this->lock);347{348tmp = dict_lookup_common(this, key);349}350UNLOCK(&this->lock);351
352if (!tmp)353return -1;354
355*data = tmp->value;356return 0;357}
358
359static int32_t360dict_set_lk(dict_t *this, char *key, const int key_len, data_t *value,361gf_boolean_t replace)362{
363data_pair_t *pair;364
365/* Search for a existing key if 'replace' is asked for */366if (replace) {367pair = dict_lookup_common(this, key);368if (pair) {369data_t *unref_data = pair->value;370pair->value = data_ref(value);371this->totkvlen += (value->len - unref_data->len);372data_unref(unref_data);373/* Indicates duplicate key */374return 0;375}376}377
378pair = GF_MALLOC(sizeof(data_pair_t) + key_len + 1,379gf_common_mt_data_pair_t);380if (caa_unlikely(!pair))381return -1;382
383pair->value = data_ref(value);384memcpy(pair->key, key, key_len + 1);385this->totkvlen += (key_len + 1 + value->len);386
387pair->next = this->members_list;388this->members_list = pair;389this->count++;390
391if (this->max_count < this->count)392this->max_count = this->count;393return 0;394}
395
396int32_t
397dict_setn(dict_t *this, char *key, const int keylen, data_t *value)398{
399int32_t ret;400
401if (!this || !value) {402gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,403"!this || !value for "404"key=%s",405key);406return -1;407}408
409LOCK(&this->lock);410
411ret = dict_set_lk(this, key, keylen, value, 1);412
413UNLOCK(&this->lock);414
415return ret;416}
417
418int32_t
419dict_addn(dict_t *this, char *key, const int keylen, data_t *value)420{
421int32_t ret;422
423if (!this || !value) {424gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,425"!this || !value for key=%s", key);426return -1;427}428
429LOCK(&this->lock);430
431ret = dict_set_lk(this, key, keylen, value, 0);432
433UNLOCK(&this->lock);434
435return ret;436}
437
438data_t *439dict_get(dict_t *this, char *key)440{
441data_pair_t *pair;442
443if (!this || !key) {444gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,445"!this || key=%s", (key) ? key : "()");446return NULL;447}448
449LOCK(&this->lock);450{451pair = dict_lookup_common(this, key);452}453UNLOCK(&this->lock);454
455if (pair)456return pair->value;457
458return NULL;459}
460
461int
462dict_key_count(dict_t *this)463{
464int ret = -1;465
466if (!this) {467gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,468"dict passed is NULL");469return ret;470}471
472LOCK(&this->lock);473{474ret = this->count;475}476UNLOCK(&this->lock);477
478return ret;479}
480
481gf_boolean_t
482dict_deln(dict_t *this, char *key, const int keylen)483{
484gf_boolean_t rc = _gf_false;485
486if (!this || !key) {487gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,488"!this || key=%s", key);489return rc;490}491
492LOCK(&this->lock);493
494data_pair_t *pair = this->members_list;495data_pair_t *prev = NULL;496
497while (pair) {498if (strcmp(pair->key, key) == 0) {499this->totkvlen -= pair->value->len;500data_unref(pair->value);501
502if (prev)503prev->next = pair->next;504else505this->members_list = pair->next;506
507this->totkvlen -= (keylen + 1);508GF_FREE(pair);509this->count--;510rc = _gf_true;511break;512}513
514prev = pair;515pair = pair->next;516}517
518UNLOCK(&this->lock);519
520return rc;521}
522
523/* removes and free all data_pair_t elements.
524* has to be called with this->lock held */
525static void526dict_clear_data(dict_t *this)527{
528data_pair_t *curr = this->members_list;529data_pair_t *next = NULL;530
531while (curr != NULL) {532next = curr->next;533data_unref(curr->value);534GF_FREE(curr);535curr = next;536}537this->count = this->totkvlen = 0;538}
539
540static void541dict_destroy(dict_t *this)542{
543if (!this) {544gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,545"dict is NULL");546return;547}548
549glusterfs_ctx_t *ctx = NULL;550uint64_t current_max = 0;551uint32_t total_pairs = this->count;552
553LOCK_DESTROY(&this->lock);554
555dict_clear_data(this);556
557free(this->extra_stdfree);558
559/* update 'ctx->stats.dict.details' using max_count */560ctx = THIS->ctx;561
562/* NOTE: below logic is not totaly race proof */563/* thread0 and thread1 gets current_max as 10 */564/* thread0 has 'this->max_count as 11 */565/* thread1 has 'this->max_count as 20 */566/* thread1 goes ahead and sets the max_dict_pairs to 20 */567/* thread0 then goes and sets it to 11 */568/* As it is for information purpose only, no functionality will be569broken by this, but a point to consider about ATOMIC macros. */
570current_max = GF_ATOMIC_GET(ctx->stats.max_dict_pairs);571if (current_max < this->max_count)572GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, this->max_count);573
574GF_ATOMIC_ADD(ctx->stats.total_pairs_used, total_pairs);575GF_ATOMIC_INC(ctx->stats.total_dicts_used);576
577mem_put(this);578
579return;580}
581
582void
583dict_unref(dict_t *this)584{
585uint32_t ref = 0;586
587if (!this) {588gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,589"dict is NULL");590return;591}592
593ref = GF_ATOMIC_DEC(this->refcount);594
595if (!ref)596dict_destroy(this);597}
598
599dict_t *600dict_ref(dict_t *this)601{
602if (!this) {603gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,604"dict is NULL");605return NULL;606}607
608GF_ATOMIC_INC(this->refcount);609return this;610}
611
612void
613data_unref(data_t *this)614{
615uint32_t ref;616
617if (!this) {618gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,619"data is NULL");620return;621}622
623ref = GF_ATOMIC_DEC(this->refcount);624
625if (!ref)626data_destroy(this);627}
628
629data_t *630data_ref(data_t *this)631{
632if (!this) {633gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,634"data is NULL");635return NULL;636}637
638GF_ATOMIC_INC(this->refcount);639
640return this;641}
642
643data_t *644data_from_int64(int64_t value)645{
646data_t *data = get_new_data();647
648if (!data) {649return NULL;650}651data->len = gf_asprintf(&data->data, "%" PRId64, value);652if (-1 == data->len) {653gf_msg_debug("dict", 0, "asprintf failed");654data_destroy(data);655return NULL;656}657data->len++; /* account for terminating NULL */658data->data_type = GF_DATA_TYPE_INT;659
660return data;661}
662
663data_t *664data_from_int32(int32_t value)665{
666data_t *data = get_new_data();667
668if (!data) {669return NULL;670}671data->len = gf_asprintf(&data->data, "%" PRId32, value);672if (-1 == data->len) {673gf_msg_debug("dict", 0, "asprintf failed");674data_destroy(data);675return NULL;676}677
678data->len++; /* account for terminating NULL */679data->data_type = GF_DATA_TYPE_INT;680
681return data;682}
683
684data_t *685data_from_int16(int16_t value)686{
687data_t *data = get_new_data();688
689if (!data) {690return NULL;691}692data->len = gf_asprintf(&data->data, "%" PRId16, value);693if (-1 == data->len) {694gf_msg_debug("dict", 0, "asprintf failed");695data_destroy(data);696return NULL;697}698
699data->len++; /* account for terminating NULL */700data->data_type = GF_DATA_TYPE_INT;701
702return data;703}
704
705data_t *706data_from_int8(int8_t value)707{
708data_t *data = get_new_data();709
710if (!data) {711return NULL;712}713data->len = gf_asprintf(&data->data, "%d", value);714if (-1 == data->len) {715gf_msg_debug("dict", 0, "asprintf failed");716data_destroy(data);717return NULL;718}719
720data->len++; /* account for terminating NULL */721data->data_type = GF_DATA_TYPE_INT;722
723return data;724}
725
726data_t *727data_from_uint64(uint64_t value)728{
729data_t *data = get_new_data();730
731if (!data) {732return NULL;733}734data->len = gf_asprintf(&data->data, "%" PRIu64, value);735if (-1 == data->len) {736gf_msg_debug("dict", 0, "asprintf failed");737data_destroy(data);738return NULL;739}740
741data->len++; /* account for terminating NULL */742data->data_type = GF_DATA_TYPE_UINT;743
744return data;745}
746
747data_t *748data_from_double(double value)749{
750data_t *data = get_new_data();751
752if (!data) {753return NULL;754}755
756data->len = gf_asprintf(&data->data, "%f", value);757if (data->len == -1) {758gf_msg_debug("dict", 0, "asprintf failed");759data_destroy(data);760return NULL;761}762data->len++; /* account for terminating NULL */763data->data_type = GF_DATA_TYPE_DOUBLE;764
765return data;766}
767
768data_t *769data_from_uint32(uint32_t value)770{
771data_t *data = get_new_data();772
773if (!data) {774return NULL;775}776data->len = gf_asprintf(&data->data, "%" PRIu32, value);777if (-1 == data->len) {778gf_msg_debug("dict", 0, "asprintf failed");779data_destroy(data);780return NULL;781}782
783data->len++; /* account for terminating NULL */784data->data_type = GF_DATA_TYPE_UINT;785
786return data;787}
788
789data_t *790data_from_uint16(uint16_t value)791{
792data_t *data = get_new_data();793
794if (!data) {795return NULL;796}797data->len = gf_asprintf(&data->data, "%" PRIu16, value);798if (-1 == data->len) {799gf_msg_debug("dict", 0, "asprintf failed");800data_destroy(data);801return NULL;802}803
804data->len++; /* account for terminating NULL */805data->data_type = GF_DATA_TYPE_UINT;806
807return data;808}
809
810static data_t *811data_from_ptr_common(void *value, gf_boolean_t is_static)812{
813/* it is valid to set 0/NULL as a value, no need to check *value */814
815data_t *data = get_new_data();816if (!data) {817return NULL;818}819
820data->data = value;821data->len = 0;822data->is_static = is_static;823
824data->data_type = GF_DATA_TYPE_PTR;825return data;826}
827
828data_t *829str_to_data(char *value)830{
831if (!value) {832gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,833"value is NULL");834return NULL;835}836
837return strn_to_data(value, strlen(value));838}
839
840data_t *841strn_to_data(char *value, const int vallen)842{
843if (!value) {844gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,845"value is NULL");846return NULL;847}848data_t *data = get_new_data();849
850if (!data) {851return NULL;852}853data->len = vallen + 1;854data->data_type = GF_DATA_TYPE_STR;855
856data->data = value;857data->is_static = _gf_true;858
859return data;860}
861
862static data_t *863data_from_dynstr(char *value)864{
865if (!value) {866gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,867"value is NULL");868return NULL;869}870
871data_t *data = get_new_data();872
873if (!data)874return NULL;875data->len = strlen(value) + 1;876data->data = value;877data->data_type = GF_DATA_TYPE_STR;878
879return data;880}
881
882data_t *883data_from_dynptr(void *value, int32_t len)884{
885data_t *data = get_new_data();886
887if (!data)888return NULL;889
890data->len = len;891data->data = value;892data->data_type = GF_DATA_TYPE_PTR;893
894return data;895}
896
897data_t *898bin_to_data(void *value, int32_t len)899{
900if (!value) {901gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,902"value is NULL");903return NULL;904}905
906data_t *data = get_new_data();907
908if (!data)909return NULL;910
911data->is_static = _gf_true;912data->len = len;913data->data = value;914
915return data;916}
917
918static char *data_type_name[GF_DATA_TYPE_MAX] = {919[GF_DATA_TYPE_UNKNOWN] = "unknown",920[GF_DATA_TYPE_STR_OLD] = "string-old-version",921[GF_DATA_TYPE_INT] = "integer",922[GF_DATA_TYPE_UINT] = "unsigned integer",923[GF_DATA_TYPE_DOUBLE] = "float",924[GF_DATA_TYPE_STR] = "string",925[GF_DATA_TYPE_PTR] = "pointer",926[GF_DATA_TYPE_GFUUID] = "gf-uuid",927[GF_DATA_TYPE_IATT] = "iatt",928[GF_DATA_TYPE_MDATA] = "mdata",929};930
931int64_t
932data_to_int64(data_t *data)933{
934VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);935
936char *endptr = NULL;937int64_t value = 0;938
939errno = 0;940value = strtoll(data->data, &endptr, 0);941
942if (endptr && *endptr != '\0')943/* Unrecognized characters at the end of string. */944errno = EINVAL;945if (errno) {946gf_msg_callingfn("dict", GF_LOG_WARNING, errno,947LG_MSG_DATA_CONVERSION_ERROR,948"Error in data conversion: '%s' can't "949"be represented as int64_t",950data->data);951return -1;952}953return value;954}
955
956/* Like above but implies signed range check. */
957
958#define DATA_TO_RANGED_SIGNED(endptr, value, data, type, min, max) \959do { \960errno = 0; \961value = strtoll(data->data, &endptr, 0); \962if (endptr && *endptr != '\0') \963errno = EINVAL; \964if (errno || value > max || value < min) { \965gf_msg_callingfn("dict", GF_LOG_WARNING, errno, \966LG_MSG_DATA_CONVERSION_ERROR, \967"Error in data conversion: '%s' can't " \968"be represented as " #type, \969data->data); \970return -1; \971} \972return (type)value; \973} while (0)974
975int32_t
976data_to_int32(data_t *data)977{
978char *endptr = NULL;979int64_t value = 0;980
981VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);982DATA_TO_RANGED_SIGNED(endptr, value, data, int32_t, INT_MIN, INT_MAX);983}
984
985int16_t
986data_to_int16(data_t *data)987{
988char *endptr = NULL;989int64_t value = 0;990
991VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);992DATA_TO_RANGED_SIGNED(endptr, value, data, int16_t, SHRT_MIN, SHRT_MAX);993}
994
995int8_t
996data_to_int8(data_t *data)997{
998char *endptr = NULL;999int64_t value = 0;1000
1001VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);1002DATA_TO_RANGED_SIGNED(endptr, value, data, int8_t, CHAR_MIN, CHAR_MAX);1003}
1004
1005uint64_t
1006data_to_uint64(data_t *data)1007{
1008VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);1009
1010char *endptr = NULL;1011uint64_t value = 0;1012
1013errno = 0;1014value = strtoull(data->data, &endptr, 0);1015
1016if (endptr && *endptr != '\0')1017errno = EINVAL;1018if (errno) {1019gf_msg_callingfn("dict", GF_LOG_WARNING, errno,1020LG_MSG_DATA_CONVERSION_ERROR,1021"Error in data conversion: '%s' can't "1022"be represented as uint64_t",1023data->data);1024return -1;1025}1026return value;1027}
1028
1029/* Like above but implies unsigned range check. */
1030
1031#define DATA_TO_RANGED_UNSIGNED(endptr, value, data, type, max) \1032do { \1033errno = 0; \1034value = strtoull(data->data, &endptr, 0); \1035if (endptr && *endptr != '\0') \1036errno = EINVAL; \1037if (errno || value > max) { \1038gf_msg_callingfn("dict", GF_LOG_WARNING, errno, \1039LG_MSG_DATA_CONVERSION_ERROR, \1040"Error in data conversion: '%s' can't " \1041"be represented as " #type, \1042data->data); \1043return -1; \1044} \1045return (type)value; \1046} while (0)1047
1048uint32_t
1049data_to_uint32(data_t *data)1050{
1051char *endptr = NULL;1052uint64_t value = 0;1053
1054VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);1055DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint32_t, UINT_MAX);1056}
1057
1058uint16_t
1059data_to_uint16(data_t *data)1060{
1061char *endptr = NULL;1062uint64_t value = 0;1063
1064VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);1065DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint16_t, USHRT_MAX);1066}
1067
1068uint8_t
1069data_to_uint8(data_t *data)1070{
1071char *endptr = NULL;1072uint64_t value = 0;1073
1074VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);1075DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint8_t, UCHAR_MAX);1076}
1077
1078char *1079data_to_str(data_t *data)1080{
1081VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, "null", NULL);1082return data->data;1083}
1084
1085void *1086data_to_ptr(data_t *data)1087{
1088VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL);1089return data->data;1090}
1091
1092void *1093data_to_bin(data_t *data)1094{
1095VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL);1096return data->data;1097}
1098
1099struct iatt *1100data_to_iatt(data_t *data, char *key)1101{
1102VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, NULL);1103
1104/* We only check for smaller size. If it's bigger we simply ignore1105* the extra data. This way it's easy to do changes in the future that
1106* pass more data but are backward compatible (if the initial contents
1107* of the struct are maintained, of course). */
1108if (data->len < sizeof(struct iatt)) {1109gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF,1110"key=%s", key, NULL);1111return NULL;1112}1113
1114return (struct iatt *)data->data;1115}
1116
1117int
1118dict_null_foreach_fn(dict_t *d, char *k, data_t *v, void *tmp)1119{
1120return 0;1121}
1122
1123int
1124dict_remove_foreach_fn(dict_t *d, char *k, data_t *v, void *_tmp)1125{
1126if (!d || !k) {1127gf_smsg("glusterfs", GF_LOG_WARNING, EINVAL, LG_MSG_KEY_OR_VALUE_NULL,1128"d=%s", d ? "key" : "dictionary", NULL);1129return -1;1130}1131
1132dict_del(d, k);1133return 0;1134}
1135
1136int
1137dict_foreach(dict_t *dict,1138int (*fn)(dict_t *this, char *key, data_t *value, void *data),1139void *data)1140{
1141int ret = dict_foreach_match(dict, dict_match_everything, NULL, fn, data);1142
1143if (ret > 0)1144ret = 0;1145
1146return ret;1147}
1148
1149/* return values:
1150-1 = failure,
11510 = no matches found,
1152+n = n number of matches
1153*/
1154int
1155dict_foreach_match(dict_t *dict,1156gf_boolean_t (*match)(dict_t *this, char *key, data_t *value,1157void *mdata),1158void *match_data,1159int (*action)(dict_t *this, char *key, data_t *value,1160void *adata),1161void *action_data)1162{
1163if (!dict || !match || !action) {1164gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,1165"dict|match|action is "1166"NULL");1167return -1;1168}1169
1170int ret;1171int count = 0;1172data_pair_t *pairs = dict->members_list;1173data_pair_t *next = NULL;1174
1175while (pairs) {1176next = pairs->next;1177if (match(dict, pairs->key, pairs->value, match_data)) {1178ret = action(dict, pairs->key, pairs->value, action_data);1179if (ret < 0)1180return ret;1181count++;1182}1183pairs = next;1184}1185
1186return count;1187}
1188
1189static gf_boolean_t1190dict_fnmatch(dict_t *d, char *k, data_t *val, void *match_data)1191{
1192return (fnmatch(match_data, k, 0) == 0);1193}
1194/* return values:
1195-1 = failure,
11960 = no matches found,
1197+n = n number of matches
1198*/
1199int
1200dict_foreach_fnmatch(dict_t *dict, char *pattern,1201int (*fn)(dict_t *this, char *key, data_t *value,1202void *data),1203void *data)1204{
1205return dict_foreach_match(dict, dict_fnmatch, pattern, fn, data);1206}
1207
1208/**
1209* dict_keys_join - pack the keys of the dictionary in a buffer.
1210*
1211* @value : buffer in which the keys will be packed (can be NULL)
1212* @size : size of the buffer which is sent (can be 0, in which case buffer
1213* is not packed but only length is returned)
1214* @dict : dictionary of which all the keys will be packed
1215* @filter_fn : keys matched in filter_fn() is counted.
1216*
1217* @return : @length of string after joining keys.
1218*
1219*/
1220
1221int
1222dict_keys_join(void *value, int size, dict_t *dict, int (*filter_fn)(char *k))1223{
1224int len = 0;1225data_pair_t *pairs = dict->members_list;1226data_pair_t *next = NULL;1227
1228while (pairs) {1229next = pairs->next;1230
1231if (filter_fn && filter_fn(pairs->key)) {1232pairs = next;1233continue;1234}1235
1236if (value && (size > len))1237strncpy(value + len, pairs->key, size - len);1238
1239len += (strlen(pairs->key) + 1);1240
1241pairs = next;1242}1243
1244return len;1245}
1246
1247static int1248dict_copy_one(dict_t *unused, char *key, data_t *value, void *newdict)1249{
1250return dict_set((dict_t *)newdict, key, (value));1251}
1252
1253dict_t *1254dict_copy(dict_t *dict, dict_t *new)1255{
1256if (!dict) {1257gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,1258"dict is NULL");1259return NULL;1260}1261
1262if (!new)1263new = get_new_dict_full();1264
1265dict_foreach(dict, dict_copy_one, new);1266
1267return new;1268}
1269
1270int
1271dict_reset(dict_t *dict)1272{
1273int32_t ret = -1;1274if (!dict) {1275gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,1276"dict is NULL");1277goto out;1278}1279
1280LOCK(&dict->lock);1281
1282dict_clear_data(dict);1283dict->members_list = NULL;1284
1285UNLOCK(&dict->lock);1286ret = 0;1287out:1288return ret;1289}
1290
1291dict_t *1292dict_copy_with_ref(dict_t *dict, dict_t *new)1293{
1294dict_t *local_new = NULL;1295
1296GF_VALIDATE_OR_GOTO("dict", dict, fail);1297
1298if (new == NULL) {1299local_new = dict_new();1300GF_VALIDATE_OR_GOTO("dict", local_new, fail);1301new = local_new;1302}1303
1304dict_foreach(dict, dict_copy_one, new);1305fail:1306return new;1307}
1308
1309/*
1310* !!!!!!! CLEANED UP CODE !!!!!!!
1311*/
1312
1313/**
1314* Common cleaned up interface:
1315*
1316* Return value: 0 success
1317* -val error, val = errno
1318*/
1319
1320static int1321dict_get_with_refn(dict_t *this, char *key, data_t **data)1322{
1323data_pair_t *pair = NULL;1324int ret = -ENOENT;1325
1326LOCK(&this->lock);1327{1328pair = dict_lookup_common(this, key);1329
1330if (pair) {1331ret = 0;1332*data = data_ref(pair->value);1333}1334}1335UNLOCK(&this->lock);1336
1337return ret;1338}
1339
1340int
1341dict_get_with_ref(dict_t *this, char *key, data_t **data)1342{
1343if (caa_unlikely(!this)) {1344/* There are possibilities where dict can be NULL. so not so critical1345* for users to know */
1346gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,1347"dict is NULL: %s", key);1348return -EINVAL;1349}1350if (caa_unlikely(!key || !data)) {1351/* is there a chance like this? then it can be a coding error, but in1352* any case, this should be caught early, so good to log it out. */
1353gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,1354"key (%s) or data ptr is NULL", key);1355
1356return -EINVAL;1357}1358return dict_get_with_refn(this, key, data);1359}
1360
1361static int1362data_to_ptr_common(data_t *data, void **val)1363{
1364int ret = 0;1365
1366if (!data) {1367ret = -EINVAL;1368goto err;1369}1370
1371*val = data->data;1372err:1373return ret;1374}
1375
1376static int1377data_to_int8_ptr(data_t *data, int8_t *val)1378{
1379int ret = 0;1380
1381if (!data || !val) {1382ret = -EINVAL;1383goto err;1384}1385
1386errno = 0;1387*val = strtol(data->data, NULL, 0);1388if (errno != 0)1389ret = -errno;1390
1391err:1392return ret;1393}
1394
1395static int1396data_to_int16_ptr(data_t *data, int16_t *val)1397{
1398int ret = 0;1399
1400if (!data || !val) {1401ret = -EINVAL;1402goto err;1403}1404
1405errno = 0;1406*val = strtol(data->data, NULL, 0);1407if (errno != 0)1408ret = -errno;1409
1410err:1411return ret;1412}
1413
1414static int1415data_to_int32_ptr(data_t *data, int32_t *val)1416{
1417int ret = 0;1418
1419if (!data || !val) {1420ret = -EINVAL;1421goto err;1422}1423
1424errno = 0;1425*val = strtol(data->data, NULL, 0);1426if (errno != 0)1427ret = -errno;1428
1429err:1430return ret;1431}
1432
1433static int1434data_to_int64_ptr(data_t *data, int64_t *val)1435{
1436int ret = 0;1437
1438if (!data || !val) {1439ret = -EINVAL;1440goto err;1441}1442
1443errno = 0;1444*val = strtoll(data->data, NULL, 0);1445if (errno != 0)1446ret = -errno;1447
1448err:1449return ret;1450}
1451
1452static int1453data_to_uint16_ptr(data_t *data, uint16_t *val)1454{
1455int ret = 0;1456
1457if (!data || !val) {1458ret = -EINVAL;1459goto err;1460}1461
1462errno = 0;1463*val = strtoul(data->data, NULL, 0);1464if (errno != 0)1465ret = -errno;1466
1467err:1468return ret;1469}
1470
1471static int1472data_to_uint32_ptr(data_t *data, uint32_t *val)1473{
1474int ret = 0;1475
1476if (!data || !val) {1477ret = -EINVAL;1478goto err;1479}1480
1481errno = 0;1482*val = strtoul(data->data, NULL, 0);1483if (errno != 0)1484ret = -errno;1485
1486err:1487return ret;1488}
1489
1490static int1491data_to_uint64_ptr(data_t *data, uint64_t *val)1492{
1493int ret = 0;1494
1495if (!data || !val) {1496ret = -EINVAL;1497goto err;1498}1499
1500errno = 0;1501*val = strtoull(data->data, NULL, 0);1502if (errno != 0)1503ret = -errno;1504
1505err:1506return ret;1507}
1508
1509static int1510data_to_double_ptr(data_t *data, double *val)1511{
1512int ret = 0;1513
1514if (!data || !val) {1515ret = -EINVAL;1516goto err;1517}1518
1519errno = 0;1520*val = strtod(data->data, NULL);1521if (errno != 0)1522ret = -errno;1523
1524err:1525return ret;1526}
1527
1528int
1529dict_get_int8(dict_t *this, char *key, int8_t *val)1530{
1531data_t *data = NULL;1532int ret = 0;1533
1534if (!val) {1535ret = -EINVAL;1536goto err;1537}1538
1539ret = dict_get_with_ref(this, key, &data);1540if (ret != 0) {1541goto err;1542}1543
1544VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);1545
1546ret = data_to_int8_ptr(data, val);1547
1548err:1549if (data)1550data_unref(data);1551return ret;1552}
1553
1554int
1555dict_set_int8(dict_t *this, char *key, int8_t val)1556{
1557data_t *data = NULL;1558int ret = 0;1559
1560data = data_from_int8(val);1561if (!data) {1562ret = -EINVAL;1563goto err;1564}1565
1566ret = dict_set(this, key, data);1567if (ret < 0)1568data_destroy(data);1569
1570err:1571return ret;1572}
1573
1574int
1575dict_get_int16(dict_t *this, char *key, int16_t *val)1576{
1577data_t *data = NULL;1578int ret = 0;1579
1580if (!val) {1581ret = -EINVAL;1582goto err;1583}1584
1585ret = dict_get_with_ref(this, key, &data);1586if (ret != 0) {1587goto err;1588}1589
1590VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);1591
1592ret = data_to_int16_ptr(data, val);1593
1594err:1595if (data)1596data_unref(data);1597return ret;1598}
1599
1600int
1601dict_set_int16(dict_t *this, char *key, int16_t val)1602{
1603data_t *data = NULL;1604int ret = 0;1605
1606data = data_from_int16(val);1607if (!data) {1608ret = -EINVAL;1609goto err;1610}1611
1612ret = dict_set(this, key, data);1613if (ret < 0)1614data_destroy(data);1615
1616err:1617return ret;1618}
1619
1620int
1621dict_get_int32n(dict_t *this, char *key, const int keylen, int32_t *val)1622{
1623data_t *data = NULL;1624int ret = 0;1625
1626if (!this || !key || !val) {1627ret = -EINVAL;1628goto err;1629}1630
1631ret = dict_get_with_refn(this, key, &data);1632if (ret != 0) {1633goto err;1634}1635
1636VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);1637
1638ret = data_to_int32_ptr(data, val);1639
1640err:1641if (data)1642data_unref(data);1643return ret;1644}
1645
1646int
1647dict_get_int32(dict_t *this, char *key, int32_t *val)1648{
1649data_t *data = NULL;1650int ret = 0;1651
1652if (!val) {1653ret = -EINVAL;1654goto err;1655}1656
1657ret = dict_get_with_ref(this, key, &data);1658if (ret != 0) {1659goto err;1660}1661
1662VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);1663
1664ret = data_to_int32_ptr(data, val);1665
1666err:1667if (data)1668data_unref(data);1669return ret;1670}
1671
1672int
1673dict_set_int32n(dict_t *this, char *key, const int keylen, int32_t val)1674{
1675data_t *data = NULL;1676int ret = 0;1677
1678data = data_from_int32(val);1679if (!data) {1680ret = -EINVAL;1681goto err;1682}1683
1684ret = dict_setn(this, key, keylen, data);1685if (ret < 0)1686data_destroy(data);1687
1688err:1689return ret;1690}
1691
1692int
1693dict_set_int32(dict_t *this, char *key, int32_t val)1694{
1695data_t *data = data_from_int32(val);1696int ret = 0;1697
1698if (!data) {1699ret = -EINVAL;1700goto err;1701}1702
1703ret = dict_set(this, key, data);1704if (ret < 0)1705data_destroy(data);1706
1707err:1708return ret;1709}
1710
1711int
1712dict_get_int64(dict_t *this, char *key, int64_t *val)1713{
1714data_t *data = NULL;1715int ret = 0;1716
1717if (!val) {1718ret = -EINVAL;1719goto err;1720}1721
1722ret = dict_get_with_ref(this, key, &data);1723if (ret != 0) {1724goto err;1725}1726
1727VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);1728
1729ret = data_to_int64_ptr(data, val);1730
1731err:1732if (data)1733data_unref(data);1734return ret;1735}
1736
1737int
1738dict_set_int64(dict_t *this, char *key, int64_t val)1739{
1740data_t *data = data_from_int64(val);1741int ret = 0;1742
1743if (!data) {1744ret = -EINVAL;1745goto err;1746}1747
1748ret = dict_set(this, key, data);1749if (ret < 0)1750data_destroy(data);1751
1752err:1753return ret;1754}
1755
1756int
1757dict_get_int64n(dict_t *this, char *key, const int keylen, int64_t *val)1758{
1759data_t *data = NULL;1760int ret = 0;1761
1762if (!this || !key || !val) {1763ret = -EINVAL;1764goto err;1765}1766
1767ret = dict_get_with_refn(this, key, &data);1768if (ret != 0) {1769goto err;1770}1771
1772VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);1773
1774ret = data_to_int64_ptr(data, val);1775
1776err:1777if (data)1778data_unref(data);1779return ret;1780}
1781
1782int
1783dict_set_int64n(dict_t *this, char *key, const int keylen, int64_t val)1784{
1785data_t *data = data_from_int64(val);1786int ret = 0;1787
1788if (!data) {1789ret = -EINVAL;1790goto err;1791}1792
1793ret = dict_setn(this, key, keylen, data);1794if (ret < 0)1795data_destroy(data);1796
1797err:1798return ret;1799}
1800
1801int
1802dict_get_uint16(dict_t *this, char *key, uint16_t *val)1803{
1804data_t *data = NULL;1805int ret = 0;1806
1807if (!val) {1808ret = -EINVAL;1809goto err;1810}1811
1812ret = dict_get_with_ref(this, key, &data);1813if (ret != 0) {1814goto err;1815}1816
1817VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL);1818
1819ret = data_to_uint16_ptr(data, val);1820
1821err:1822if (data)1823data_unref(data);1824return ret;1825}
1826
1827int
1828dict_set_uint16(dict_t *this, char *key, uint16_t val)1829{
1830data_t *data = data_from_uint16(val);1831int ret = 0;1832
1833if (!data) {1834ret = -EINVAL;1835goto err;1836}1837
1838ret = dict_set(this, key, data);1839if (ret < 0)1840data_destroy(data);1841
1842err:1843return ret;1844}
1845
1846int
1847dict_get_uint32(dict_t *this, char *key, uint32_t *val)1848{
1849data_t *data = NULL;1850int ret = 0;1851
1852if (!val) {1853ret = -EINVAL;1854goto err;1855}1856
1857ret = dict_get_with_ref(this, key, &data);1858if (ret != 0) {1859goto err;1860}1861
1862VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL);1863
1864ret = data_to_uint32_ptr(data, val);1865
1866err:1867if (data)1868data_unref(data);1869return ret;1870}
1871
1872int
1873dict_set_uint32(dict_t *this, char *key, uint32_t val)1874{
1875data_t *data = data_from_uint32(val);1876int ret = 0;1877
1878if (!data) {1879ret = -EINVAL;1880goto err;1881}1882
1883ret = dict_set(this, key, data);1884if (ret < 0)1885data_destroy(data);1886
1887err:1888return ret;1889}
1890
1891int
1892dict_get_uint64(dict_t *this, char *key, uint64_t *val)1893{
1894data_t *data = NULL;1895int ret = 0;1896
1897if (!val) {1898ret = -EINVAL;1899goto err;1900}1901
1902ret = dict_get_with_ref(this, key, &data);1903if (ret != 0) {1904goto err;1905}1906
1907VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL);1908
1909ret = data_to_uint64_ptr(data, val);1910
1911err:1912if (data)1913data_unref(data);1914return ret;1915}
1916
1917int
1918dict_set_uint64(dict_t *this, char *key, uint64_t val)1919{
1920data_t *data = data_from_uint64(val);1921int ret = 0;1922
1923if (!data) {1924ret = -EINVAL;1925goto err;1926}1927
1928ret = dict_set(this, key, data);1929if (ret < 0)1930data_destroy(data);1931
1932err:1933return ret;1934}
1935
1936/*
1937* dict_check_flag can be used to check a one bit flag in an array of flags
1938* The flag argument indicates the bit position (within the array of bits).
1939* Currently limited to max of 256 flags for a key.
1940* return value,
1941* 1 : flag is set
1942* 0 : flag is not set
1943* <0: Error
1944*/
1945int
1946dict_check_flag(dict_t *this, char *key, int flag)1947{
1948data_t *data = NULL;1949int ret = -ENOENT;1950
1951ret = dict_get_with_ref(this, key, &data);1952if (ret < 0) {1953return ret;1954}1955
1956if (BIT_VALUE((unsigned char *)(data->data), flag))1957ret = 1;1958else1959ret = 0;1960
1961data_unref(data);1962return ret;1963}
1964
1965/*
1966* _dict_modify_flag can be used to set/clear a bit flag in an array of flags
1967* flag: indicates the bit position. limited to max of DICT_MAX_FLAGS.
1968* op: Indicates operation DICT_FLAG_SET / DICT_FLAG_CLEAR
1969*/
1970static int1971_dict_modify_flag(dict_t *this, char *key, int flag, int op)1972{
1973data_t *data = NULL;1974int ret = 0;1975data_pair_t *pair = NULL;1976char *ptr = NULL;1977size_t keylen;1978
1979if (!this || !key) {1980gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,1981"dict OR key (%s) is NULL", key);1982ret = -EINVAL;1983goto err;1984}1985
1986/*1987* Using a size of 32 bytes to support max of 256
1988* flags in a single key. This should be suffcient.
1989*/
1990GF_ASSERT(flag >= 0 && flag < DICT_MAX_FLAGS);1991
1992LOCK(&this->lock);1993{1994pair = dict_lookup_common(this, key);1995
1996if (pair) {1997data = pair->value;1998if (op == DICT_FLAG_SET)1999BIT_SET((unsigned char *)(data->data), flag);2000else2001BIT_CLEAR((unsigned char *)(data->data), flag);2002} else {2003ptr = GF_CALLOC(1, DICT_MAX_FLAGS / 8, gf_common_mt_char);2004if (!ptr) {2005gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY,2006"flag bit array", NULL);2007ret = -ENOMEM;2008goto err;2009}2010
2011data = data_from_dynptr(ptr, DICT_MAX_FLAGS / 8);2012
2013if (!data) {2014gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, "data",2015NULL);2016GF_FREE(ptr);2017ret = -ENOMEM;2018goto err;2019}2020
2021if (op == DICT_FLAG_SET)2022BIT_SET((unsigned char *)(data->data), flag);2023else2024BIT_CLEAR((unsigned char *)(data->data), flag);2025
2026keylen = strlen(key) + 1; // including terminating NULL char2027pair = GF_MALLOC(sizeof(data_pair_t) + keylen,2028gf_common_mt_data_pair_t);2029if (caa_unlikely(!pair)) {2030gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY,2031"dict pair", NULL);2032ret = -ENOMEM;2033goto err;2034}2035
2036pair->value = data_ref(data);2037memcpy(pair->key, key, keylen);2038this->totkvlen += (keylen + data->len);2039
2040pair->next = this->members_list;2041this->members_list = pair;2042this->count++;2043
2044if (this->max_count < this->count)2045this->max_count = this->count;2046}2047}2048
2049UNLOCK(&this->lock);2050return 0;2051
2052err:2053if (key && this)2054UNLOCK(&this->lock);2055
2056if (pair)2057GF_FREE(pair);2058
2059if (data)2060data_destroy(data);2061
2062gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_DICT_SET_FAILED, "key=%s", key,2063NULL);2064
2065return ret;2066}
2067
2068/*
2069* Todo:
2070* Add below primitives as needed:
2071* dict_check_flags(this, key, flag...): variadic function to check
2072* multiple flags at a time.
2073* dict_set_flags(this, key, flag...): set multiple flags
2074* dict_clear_flags(this, key, flag...): reset multiple flags
2075*/
2076
2077int
2078dict_set_flag(dict_t *this, char *key, int flag)2079{
2080return _dict_modify_flag(this, key, flag, DICT_FLAG_SET);2081}
2082
2083int
2084dict_clear_flag(dict_t *this, char *key, int flag)2085{
2086return _dict_modify_flag(this, key, flag, DICT_FLAG_CLEAR);2087}
2088
2089int
2090dict_get_double(dict_t *this, char *key, double *val)2091{
2092data_t *data = NULL;2093int ret = 0;2094
2095if (!val) {2096ret = -EINVAL;2097goto err;2098}2099
2100ret = dict_get_with_ref(this, key, &data);2101if (ret != 0) {2102goto err;2103}2104
2105VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_DOUBLE, key, -EINVAL);2106
2107ret = data_to_double_ptr(data, val);2108
2109err:2110if (data)2111data_unref(data);2112return ret;2113}
2114
2115int
2116dict_set_double(dict_t *this, char *key, double val)2117{
2118data_t *data = data_from_double(val);2119int ret = 0;2120
2121if (!data) {2122ret = -EINVAL;2123goto err;2124}2125
2126ret = dict_set(this, key, data);2127if (ret < 0)2128data_destroy(data);2129
2130err:2131return ret;2132}
2133
2134int
2135dict_set_static_ptr(dict_t *this, char *key, void *ptr)2136{
2137data_t *data = data_from_ptr_common(ptr, _gf_true);2138int ret = 0;2139
2140if (!data) {2141ret = -EINVAL;2142goto err;2143}2144
2145ret = dict_set(this, key, data);2146if (ret < 0)2147data_destroy(data);2148
2149err:2150return ret;2151}
2152
2153int
2154dict_set_dynptr(dict_t *this, char *key, void *ptr, size_t len)2155{
2156data_t *data = data_from_dynptr(ptr, len);2157int ret = 0;2158
2159if (!data) {2160ret = -EINVAL;2161goto err;2162}2163
2164ret = dict_set(this, key, data);2165if (ret < 0)2166data_destroy(data);2167
2168err:2169return ret;2170}
2171
2172int
2173dict_get_ptr(dict_t *this, char *key, void **ptr)2174{
2175data_t *data = NULL;2176int ret = 0;2177
2178if (!ptr) {2179ret = -EINVAL;2180goto err;2181}2182
2183ret = dict_get_with_ref(this, key, &data);2184if (ret != 0) {2185goto err;2186}2187
2188VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL);2189
2190ret = data_to_ptr_common(data, ptr);2191if (ret != 0) {2192goto err;2193}2194
2195err:2196if (data)2197data_unref(data);2198
2199return ret;2200}
2201
2202int
2203dict_get_ptr_and_len(dict_t *this, char *key, void **ptr, int *len)2204{
2205data_t *data = NULL;2206int ret = 0;2207
2208if (!ptr) {2209ret = -EINVAL;2210goto err;2211}2212
2213ret = dict_get_with_ref(this, key, &data);2214if (ret != 0) {2215goto err;2216}2217
2218VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL);2219
2220*len = data->len;2221
2222ret = data_to_ptr_common(data, ptr);2223if (ret != 0) {2224goto err;2225}2226
2227err:2228if (data)2229data_unref(data);2230
2231return ret;2232}
2233
2234/* Get string - with known key length */
2235int
2236dict_get_strn(dict_t *this, char *key, const int keylen, char **str)2237{
2238data_t *data = NULL;2239int ret = -EINVAL;2240
2241if (!this || !key || !str) {2242goto err;2243}2244ret = dict_get_with_refn(this, key, &data);2245if (ret < 0) {2246goto err;2247}2248
2249VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL);2250
2251*str = data->data;2252
2253err:2254if (data)2255data_unref(data);2256
2257return ret;2258}
2259
2260int
2261dict_get_str(dict_t *this, char *key, char **str)2262{
2263data_t *data = NULL;2264int ret = -EINVAL;2265
2266if (!str) {2267goto err;2268}2269ret = dict_get_with_ref(this, key, &data);2270if (ret < 0) {2271goto err;2272}2273
2274VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL);2275
2276*str = data->data;2277
2278err:2279if (data)2280data_unref(data);2281
2282return ret;2283}
2284
2285int
2286dict_set_str(dict_t *this, char *key, char *str)2287{
2288data_t *data = str_to_data(str);2289int ret = 0;2290
2291if (!data) {2292ret = -EINVAL;2293goto err;2294}2295
2296ret = dict_set(this, key, data);2297if (ret < 0)2298data_destroy(data);2299
2300err:2301return ret;2302}
2303
2304/* Set string - with known key length */
2305int
2306dict_set_strn(dict_t *this, char *key, const int keylen, char *str)2307{
2308data_t *data = NULL;2309int ret = 0;2310
2311data = str_to_data(str);2312if (!data) {2313ret = -EINVAL;2314goto err;2315}2316
2317ret = dict_setn(this, key, keylen, data);2318if (ret < 0)2319data_destroy(data);2320
2321err:2322return ret;2323}
2324
2325/* Set string - with known key length and known value length */
2326int
2327dict_set_nstrn(dict_t *this, char *key, const int keylen, char *str,2328const int vallen)2329{
2330data_t *data = strn_to_data(str, vallen);2331int ret = 0;2332
2333if (!data) {2334ret = -EINVAL;2335goto err;2336}2337
2338ret = dict_setn(this, key, keylen, data);2339if (ret < 0)2340data_destroy(data);2341
2342err:2343return ret;2344}
2345
2346int
2347dict_set_dynstr_with_alloc(dict_t *this, char *key, const char *str)2348{
2349char *alloc_str = gf_strdup(str);2350int ret = -1;2351
2352if (!alloc_str)2353return ret;2354
2355ret = dict_set_dynstr(this, key, alloc_str);2356if (ret == -EINVAL)2357GF_FREE(alloc_str);2358
2359return ret;2360}
2361
2362int
2363dict_set_dynstr(dict_t *this, char *key, char *str)2364{
2365const int keylen = strlen(key);2366return dict_set_dynstrn(this, key, keylen, str);2367}
2368
2369int
2370dict_set_dynstrn(dict_t *this, char *key, const int keylen, char *str)2371{
2372data_t *data = data_from_dynstr(str);2373int ret = 0;2374
2375if (!data) {2376ret = -EINVAL;2377goto err;2378}2379
2380ret = dict_setn(this, key, keylen, data);2381if (ret < 0)2382data_destroy(data);2383
2384err:2385return ret;2386}
2387
2388/* This function is called only by the volgen for now.
2389Check how else you can handle it */
2390int
2391dict_set_option(dict_t *this, char *key, char *str)2392{
2393data_t *data = data_from_dynstr(str);2394int ret = 0;2395
2396if (!data) {2397ret = -EINVAL;2398goto err;2399}2400
2401data->data_type = GF_DATA_TYPE_STR_OLD;2402ret = dict_set(this, key, data);2403if (ret < 0)2404data_destroy(data);2405err:2406return ret;2407}
2408
2409int
2410dict_add_dynstr_with_alloc(dict_t *this, char *key, char *str)2411{
2412data_t *data = NULL;2413int ret = 0;2414char *alloc_str = gf_strdup(str);2415
2416if (!alloc_str)2417goto out;2418
2419data = data_from_dynstr(alloc_str);2420if (!data) {2421GF_FREE(alloc_str);2422ret = -EINVAL;2423goto out;2424}2425
2426ret = dict_add(this, key, data);2427if (ret < 0)2428data_destroy(data);2429
2430out:2431return ret;2432}
2433
2434int
2435dict_get_bin(dict_t *this, char *key, void **bin)2436{
2437data_t *data = NULL;2438int ret = -EINVAL;2439
2440if (!bin) {2441goto err;2442}2443
2444ret = dict_get_with_ref(this, key, &data);2445if (ret < 0) {2446goto err;2447}2448
2449VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, ret);2450
2451*bin = data->data;2452
2453err:2454if (data)2455data_unref(data);2456
2457return ret;2458}
2459
2460/********************************************************************
2461*
2462* dict_setn_bin_common:
2463* This is the common function to set key and its value in
2464* dictionary. Flag(is_static) should be set appropriately based
2465* on the type of memory type used for value(*ptr). If flag is set
2466* to false value(*ptr) will be freed using GF_FREE() on destroy.
2467*
2468*******************************************************************/
2469static int2470dict_setn_bin_common(dict_t *this, char *key, const int keylen, void *ptr,2471size_t size, gf_boolean_t is_static,2472gf_dict_data_type_t type)2473{
2474data_t *data = NULL;2475int ret = 0;2476
2477if (!ptr || (size > DICT_KEY_VALUE_MAX_SIZE)) {2478ret = -EINVAL;2479goto err;2480}2481
2482data = bin_to_data(ptr, size);2483if (!data) {2484ret = -EINVAL;2485goto err;2486}2487
2488data->is_static = is_static;2489data->data_type = type;2490
2491ret = dict_setn(this, key, keylen, data);2492if (ret < 0) {2493/* don't free data->data, let callers handle it */2494data->data = NULL;2495data_destroy(data);2496}2497
2498err:2499return ret;2500}
2501
2502/********************************************************************
2503*
2504* dict_setn_bin:
2505* Set key and its value in the dictionary. This function should
2506* be called if the value is stored in dynamic memory.
2507*
2508*******************************************************************/
2509int
2510dict_setn_bin(dict_t *this, char *key, const int keylen, void *ptr, size_t size)2511{
2512return dict_setn_bin_common(this, key, keylen, ptr, size, _gf_false,2513GF_DATA_TYPE_PTR);2514}
2515
2516/********************************************************************
2517*
2518* dict_setn_static_bin:
2519* Set key and its value in the dictionary. This function should
2520* be called if the value is stored in static memory.
2521*
2522*******************************************************************/
2523int
2524dict_setn_static_bin(dict_t *this, char *key, const int keylen, void *ptr,2525size_t size)2526{
2527return dict_setn_bin_common(this, key, keylen, ptr, size, _gf_true,2528GF_DATA_TYPE_PTR);2529}
2530
2531int
2532dict_setn_gfuuid(dict_t *this, char *key, const int keylen, uuid_t gfid,2533bool is_static)2534{
2535return dict_setn_bin_common(this, key, keylen, gfid, sizeof(uuid_t),2536is_static, GF_DATA_TYPE_GFUUID);2537}
2538
2539int
2540dict_get_gfuuid(dict_t *this, char *key, uuid_t *gfid)2541{
2542data_t *data = NULL;2543int ret = -EINVAL;2544
2545if (!gfid) {2546goto err;2547}2548ret = dict_get_with_ref(this, key, &data);2549if (ret < 0) {2550goto err;2551}2552
2553VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_GFUUID, key, -EINVAL);2554
2555memcpy(*gfid, data->data, min(data->len, sizeof(uuid_t)));2556
2557err:2558if (data)2559data_unref(data);2560
2561return ret;2562}
2563
2564int
2565dict_set_mdata(dict_t *this, char *key, struct mdata_iatt *mdata,2566bool is_static)2567{
2568return dict_setn_bin_common(this, key, strlen(key), mdata,2569sizeof(struct mdata_iatt), is_static,2570GF_DATA_TYPE_MDATA);2571}
2572
2573int
2574dict_get_mdata(dict_t *this, char *key, struct mdata_iatt *mdata)2575{
2576data_t *data = NULL;2577int ret = -EINVAL;2578
2579if (!mdata) {2580goto err;2581}2582ret = dict_get_with_ref(this, key, &data);2583if (ret < 0) {2584goto err;2585}2586
2587VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_MDATA, key, -EINVAL);2588if (data->len < sizeof(struct mdata_iatt)) {2589gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF,2590"key=%s", key, NULL);2591ret = -ENOBUFS;2592goto err;2593}2594
2595memcpy(mdata, data->data, min(data->len, sizeof(struct mdata_iatt)));2596
2597err:2598if (data)2599data_unref(data);2600
2601return ret;2602}
2603
2604int
2605dict_set_iatt(dict_t *this, char *key, struct iatt *iatt, bool is_static)2606{
2607return dict_setn_bin_common(this, key, strlen(key), iatt,2608sizeof(struct iatt), is_static,2609GF_DATA_TYPE_IATT);2610}
2611
2612int
2613dict_get_iatt(dict_t *this, char *key, struct iatt *iatt)2614{
2615data_t *data = NULL;2616int ret = -EINVAL;2617
2618if (!iatt) {2619goto err;2620}2621ret = dict_get_with_ref(this, key, &data);2622if (ret < 0) {2623goto err;2624}2625
2626VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, -EINVAL);2627
2628memcpy(iatt, data->data, min(data->len, sizeof(struct iatt)));2629
2630err:2631if (data)2632data_unref(data);2633
2634return ret;2635}
2636
2637/**
2638* dict_get_str_boolean - get a boolean value based on string representation.
2639*
2640* @this : dictionary
2641* @key : dictionary key queried
2642* @default_val : default value if key not found
2643*
2644* @return : @default_val if key not found
2645* : boolean interpretation of @this[@key] if it makes sense
2646* (ie., "on", "true", "enable" ...)
2647* : -1 if error occurs or @this[@key] doesn't make sens as
2648* boolean
2649*
2650* So if you query a boolean option, then via @default_val you can choose
2651* between following patterns:
2652*
2653* - fall back to _gf_false if @key is not set [@default_val = 0]
2654* - fall back to _gf_true if @key is not set [@default_val = 1]
2655* - regard as failure if @key is not set [@default_val = -1]
2656* - handle specially (not as error) if @key is not set
2657* [@default_val = anything else]
2658*/
2659
2660int
2661dict_get_str_boolean(dict_t *this, char *key, int default_val)2662{
2663data_t *data = NULL;2664gf_boolean_t boo = _gf_false;2665int ret = 0;2666
2667ret = dict_get_with_ref(this, key, &data);2668if (ret < 0) {2669if (ret == -ENOENT)2670ret = default_val;2671else2672ret = -1;2673goto err;2674}2675
2676VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);2677
2678ret = gf_strn2boolean(data->data, data->len - 1, &boo);2679if (ret == -1)2680goto err;2681
2682ret = boo;2683
2684err:2685if (data)2686data_unref(data);2687
2688return ret;2689}
2690
2691int
2692dict_rename_key(dict_t *this, char *key, char *replace_key)2693{
2694data_pair_t *pair = NULL;2695int ret = -EINVAL;2696int replacekey_len = 0;2697
2698/* replacing a key by itself is a NO-OP */2699if (strcmp(key, replace_key) == 0)2700return 0;2701
2702if (!this) {2703gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,2704"dict is NULL");2705return ret;2706}2707
2708replacekey_len = strlen(replace_key);2709
2710LOCK(&this->lock);2711{2712/* no need to data_ref(pair->value), dict_set_lk() does it */2713pair = dict_lookup_common(this, key);2714if (!pair)2715ret = -ENODATA;2716else2717ret = dict_set_lk(this, replace_key, replacekey_len, pair->value,27181);2719}2720UNLOCK(&this->lock);2721
2722if (!ret)2723/* only delete the key on success */2724dict_del(this, key);2725
2726return ret;2727}
2728
2729/**
2730* Serialization format:
2731* -------- -------- -------- ----------- -------------
2732* | count | key len | val len | key \0| value
2733* ---------------------------------------- -------------
2734* 4 4 4 <key len> <value len>
2735*/
2736
2737/**
2738* dict_serialized_length_lk - return the length of serialized dict. This
2739* procedure has to be called with this->lock held.
2740*
2741* @this : dict to be serialized
2742* @return: success: len
2743* : failure: -errno
2744*/
2745
2746unsigned int2747dict_serialized_length_lk(dict_t *this)2748{
2749unsigned int count = this->count;2750const unsigned int keyhdrlen = DICT_DATA_HDR_KEY_LEN +2751DICT_DATA_HDR_VAL_LEN;2752
2753return DICT_HDR_LEN + this->totkvlen + (count * keyhdrlen);2754}
2755
2756/**
2757* dict_serialize_lk - serialize a dictionary into a buffer. This procedure has
2758* to be called with this->lock held.
2759*
2760* @this: dict to serialize
2761* @buf: buffer to serialize into. This must be
2762* at least dict_serialized_length (this) large
2763*
2764* @return: success: 0
2765* failure: -errno
2766*/
2767
2768static int2769dict_serialize_lk(dict_t *this, char *buf)2770{
2771int ret = -1;2772data_pair_t *pair = this->members_list;2773uint32_t count = this->count;2774uint32_t keylen = 0;2775uint32_t netword = 0;2776
2777if (!buf) {2778gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, NULL);2779goto out;2780}2781
2782netword = htobe32(count);2783memcpy(buf, &netword, sizeof(netword));2784buf += DICT_HDR_LEN;2785
2786while (count) {2787if (!pair) {2788gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT,2789NULL);2790goto out;2791}2792
2793keylen = strlen(pair->key);2794netword = htobe32(keylen);2795memcpy(buf, &netword, sizeof(netword));2796buf += DICT_DATA_HDR_KEY_LEN;2797
2798if (!pair->value) {2799gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, NULL);2800goto out;2801}2802
2803netword = htobe32(pair->value->len);2804memcpy(buf, &netword, sizeof(netword));2805buf += DICT_DATA_HDR_VAL_LEN;2806
2807memcpy(buf, pair->key, keylen);2808buf += keylen;2809*buf++ = '\0';2810
2811if (pair->value->data) {2812memcpy(buf, pair->value->data, pair->value->len);2813buf += pair->value->len;2814}2815
2816pair = pair->next;2817count--;2818}2819
2820ret = 0;2821out:2822return ret;2823}
2824
2825/**
2826* dict_unserialize - unserialize a buffer into a dict
2827*
2828* @buf: buf containing serialized dict
2829* @size: size of the @buf
2830* @fill: dict to fill in
2831*
2832* @return: success: 0
2833* failure: -errno
2834*/
2835
2836int32_t
2837dict_unserialize(char *orig_buf, int32_t size, dict_t **fill)2838{
2839char *buf = orig_buf;2840int ret = -1;2841uint32_t count = 0;2842int i = 0;2843
2844data_t *value = NULL;2845char *key = NULL;2846int32_t keylen = 0;2847int32_t vallen = 0;2848int32_t hostord = 0;2849
2850if (!buf) {2851gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,2852"buf is null!");2853goto out;2854}2855
2856if (size == 0) {2857gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,2858"size is 0!");2859goto out;2860}2861
2862if (!fill) {2863gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,2864"fill is null!");2865goto out;2866}2867
2868if (!*fill) {2869gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,2870"*fill is null!");2871goto out;2872}2873
2874if ((buf + DICT_HDR_LEN) > (orig_buf + size)) {2875gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,2876"undersized buffer "2877"passed. available (%lu) < required (%lu)",2878(long)(orig_buf + size), (long)(buf + DICT_HDR_LEN));2879goto out;2880}2881
2882memcpy(&hostord, buf, sizeof(hostord));2883count = be32toh(hostord);2884buf += DICT_HDR_LEN;2885
2886/* count will be set by the dict_set's below */2887(*fill)->count = 0;2888
2889for (i = 0; i < count; i++) {2890if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) {2891gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,2892"undersized "2893"buffer passed. available (%lu) < "2894"required (%lu)",2895(long)(orig_buf + size),2896(long)(buf + DICT_DATA_HDR_KEY_LEN));2897goto out;2898}2899memcpy(&hostord, buf, sizeof(hostord));2900keylen = be32toh(hostord);2901buf += DICT_DATA_HDR_KEY_LEN;2902
2903if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) {2904gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,2905"undersized "2906"buffer passed. available (%lu) < "2907"required (%lu)",2908(long)(orig_buf + size),2909(long)(buf + DICT_DATA_HDR_VAL_LEN));2910goto out;2911}2912memcpy(&hostord, buf, sizeof(hostord));2913vallen = be32toh(hostord);2914buf += DICT_DATA_HDR_VAL_LEN;2915
2916if ((keylen < 0) || (vallen < 0)) {2917gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,2918"undersized length passed "2919"key:%d val:%d",2920keylen, vallen);2921goto out;2922}2923if ((buf + keylen) > (orig_buf + size)) {2924gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,2925"undersized buffer passed. "2926"available (%lu) < required (%lu)",2927(long)(orig_buf + size), (long)(buf + keylen));2928goto out;2929}2930key = buf;2931buf += keylen + 1; /* for '\0' */2932
2933if ((buf + vallen) > (orig_buf + size)) {2934gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,2935"undersized buffer passed. "2936"available (%lu) < required (%lu)",2937(long)(orig_buf + size), (long)(buf + vallen));2938goto out;2939}2940value = get_new_data();2941
2942if (!value) {2943ret = -1;2944goto out;2945}2946value->len = vallen;2947value->data = gf_memdup(buf, vallen);2948value->data_type = GF_DATA_TYPE_STR_OLD;2949value->is_static = _gf_false;2950buf += vallen;2951
2952ret = dict_addn(*fill, key, keylen, value);2953if (ret < 0)2954goto out;2955}2956
2957ret = 0;2958out:2959return ret;2960}
2961
2962/**
2963* dict_allocate_and_serialize - serialize a dictionary into an allocated buffer
2964*
2965* @this: dict to serialize
2966* @buf: pointer to pointer to character. The allocated buffer is stored in
2967* this pointer. The buffer has to be freed by the caller.
2968*
2969* @return: success: 0
2970* failure: -errno
2971*/
2972
2973int32_t
2974dict_allocate_and_serialize(dict_t *this, char **buf, u_int *length)2975{
2976int ret = -EINVAL;2977ssize_t len = 0;2978
2979if (!this || !buf) {2980gf_msg_debug("dict", 0, "dict OR buf is NULL");2981goto out;2982}2983
2984LOCK(&this->lock);2985{2986len = dict_serialized_length_lk(this);2987
2988*buf = GF_MALLOC(len, gf_common_mt_char);2989if (*buf == NULL) {2990ret = -ENOMEM;2991goto unlock;2992}2993
2994ret = dict_serialize_lk(this, *buf);2995if (ret < 0) {2996GF_FREE(*buf);2997*buf = NULL;2998goto unlock;2999}3000
3001if (length != NULL) {3002*length = len;3003}3004}3005unlock:3006UNLOCK(&this->lock);3007out:3008return ret;3009}
3010
3011/**
3012* dict_serialize_value_with_delim_lk: serialize the values in the dictionary
3013* into a buffer separated by delimiter (except the last)
3014*
3015* @this : dictionary to serialize
3016* @buf : the buffer to store the serialized data
3017* @serz_len : the length of the serialized data (excluding the last delimiter)
3018* @delimiter : the delimiter to separate the values
3019*
3020* @return : 0 -> success
3021* : -errno -> failure
3022*/
3023static int3024dict_serialize_value_with_delim_lk(dict_t *this, char *buf, int32_t *serz_len,3025char delimiter)3026{
3027int ret = -1;3028uint32_t count = this->count;3029int32_t vallen = 0;3030int32_t total_len = 0;3031data_pair_t *pair = this->members_list;3032
3033while (count) {3034if (!pair) {3035gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT,3036NULL);3037goto out;3038}3039
3040if (!pair->value) {3041gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_KEY_OR_VALUE_NULL, NULL);3042goto out;3043}3044
3045if (!pair->value->data) {3046gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_VALUE_IN_DICT, NULL);3047goto out;3048}3049
3050vallen = pair->value->len - 1; // length includes \03051memcpy(buf, pair->value->data, vallen);3052buf += vallen;3053*buf++ = delimiter;3054
3055total_len += (vallen + 1);3056
3057pair = pair->next;3058count--;3059}3060
3061*--buf = '\0'; // remove the last delimiter3062total_len--; // adjust the length3063ret = 0;3064
3065if (serz_len)3066*serz_len = total_len;3067
3068out:3069return ret;3070}
3071
3072int
3073dict_serialize_value_with_delim(dict_t *this, char *buf, int32_t *serz_len,3074char delimiter)3075{
3076int ret = -1;3077
3078if (!this || !buf) {3079gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,3080"dict is null!");3081goto out;3082}3083
3084LOCK(&this->lock);3085{3086ret = dict_serialize_value_with_delim_lk(this, buf, serz_len,3087delimiter);3088}3089UNLOCK(&this->lock);3090out:3091return ret;3092}
3093
3094int
3095dict_dump_to_str(dict_t *dict, char *dump, int dumpsize, char *format)3096{
3097int ret = 0;3098int dumplen = 0;3099data_pair_t *trav = NULL;3100
3101if (!dict)3102return 0;3103
3104for (trav = dict->members_list; trav; trav = trav->next) {3105ret = snprintf(&dump[dumplen], dumpsize - dumplen, format, trav->key,3106trav->value->data);3107if ((ret == -1) || !ret)3108return ret;3109
3110dumplen += ret;3111}3112return 0;3113}
3114
3115void
3116dict_dump_to_log(dict_t *dict)3117{
3118int ret = -1;3119char *dump = NULL;3120const int dump_size = 64 * 1024;3121char *format = "(%s:%s)";3122
3123if (!dict) {3124gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,3125"dict is NULL");3126goto out;3127}3128
3129dump = GF_MALLOC(dump_size, gf_common_mt_char);3130if (!dump) {3131gf_msg_callingfn("dict", GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY,3132"dump buffer is NULL");3133goto out;3134}3135
3136ret = dict_dump_to_str(dict, dump, dump_size, format);3137if (ret) {3138gf_smsg("dict", GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, NULL);3139goto out;3140}3141gf_smsg("dict", GF_LOG_INFO, 0, LG_MSG_DICT_ERROR, "dict=%p", dict,3142"dump=%s", dump, NULL);3143out:3144GF_FREE(dump);3145
3146return;3147}
3148
3149void
3150dict_dump_to_statedump(dict_t *dict, char *dict_name, char *domain)3151{
3152int ret = -1;3153char *dump = NULL;3154const int dump_size = 64 * 1024;3155char key[4096] = {31560,3157};3158char *format = "\n\t%s:%s";3159
3160if (!dict) {3161gf_msg_callingfn(domain, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,3162"dict is NULL");3163goto out;3164}3165
3166dump = GF_MALLOC(dump_size, gf_common_mt_char);3167if (!dump) {3168gf_msg_callingfn(domain, GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY,3169"dump buffer is NULL");3170goto out;3171}3172
3173ret = dict_dump_to_str(dict, dump, dump_size, format);3174if (ret) {3175gf_smsg(domain, GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, "name=%s",3176dict_name, NULL);3177goto out;3178}3179gf_proc_dump_build_key(key, domain, "%s", dict_name);3180gf_proc_dump_write(key, "%s", dump);3181
3182out:3183GF_FREE(dump);3184
3185return;3186}
3187
3188dict_t *3189dict_for_key_value(const char *name, const char *value, size_t size,3190gf_boolean_t is_static)3191{
3192dict_t *xattr = dict_new();3193int ret = 0;3194
3195if (!xattr)3196return NULL;3197
3198if (is_static)3199ret = dict_set_static_bin(xattr, (char *)name, (void *)value, size);3200else3201ret = dict_set_bin(xattr, (char *)name, (void *)value, size);3202
3203if (ret) {3204dict_destroy(xattr);3205xattr = NULL;3206}3207
3208return xattr;3209}
3210
3211/*
3212* "strings" should be NULL terminated strings array.
3213*/
3214int
3215dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result)3216{
3217int i = 0;3218
3219if (!dict || !strings || !result)3220return -EINVAL;3221
3222LOCK(&dict->lock);3223{3224for (i = 0; strings[i]; i++) {3225if (dict_lookup_common(dict, strings[i])) {3226*result = _gf_true;3227goto unlock;3228}3229}3230*result = _gf_false;3231}3232unlock:3233UNLOCK(&dict->lock);3234return 0;3235}
3236
3237/* Popluate specific dictionary on the basis of passed key array at the
3238time of unserialize buffer
3239*/
3240int32_t
3241dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,3242char **suffix_key_arr, dict_t **specific_dict,3243int totkeycount)3244{
3245char *buf = orig_buf;3246int ret = -1;3247uint32_t count = 0;3248int i = 0;3249int j = 0;3250
3251data_t *value = NULL;3252char *key = NULL;3253int32_t keylen = 0;3254int32_t vallen = 0;3255int32_t hostord = 0;3256int32_t keylenarr[totkeycount];3257
3258if (!buf) {3259gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,3260"buf is null!");3261goto out;3262}3263
3264if (size == 0) {3265gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,3266"size is 0!");3267goto out;3268}3269
3270if (!fill) {3271gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,3272"fill is null!");3273goto out;3274}3275
3276if (!*fill) {3277gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,3278"*fill is null!");3279goto out;3280}3281
3282if ((buf + DICT_HDR_LEN) > (orig_buf + size)) {3283gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,3284"undersized buffer "3285"passed. available (%lu) < required (%lu)",3286(long)(orig_buf + size), (long)(buf + DICT_HDR_LEN));3287goto out;3288}3289
3290memcpy(&hostord, buf, sizeof(hostord));3291count = be32toh(hostord);3292buf += DICT_HDR_LEN;3293
3294/* Compute specific key length and save in array */3295for (i = 0; i < totkeycount; i++) {3296keylenarr[i] = strlen(suffix_key_arr[i]);3297}3298
3299for (i = 0; i < count; i++) {3300if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) {3301gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,3302"undersized "3303"buffer passed. available (%lu) < "3304"required (%lu)",3305(long)(orig_buf + size),3306(long)(buf + DICT_DATA_HDR_KEY_LEN));3307goto out;3308}3309memcpy(&hostord, buf, sizeof(hostord));3310keylen = be32toh(hostord);3311buf += DICT_DATA_HDR_KEY_LEN;3312
3313if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) {3314gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,3315"undersized "3316"buffer passed. available (%lu) < "3317"required (%lu)",3318(long)(orig_buf + size),3319(long)(buf + DICT_DATA_HDR_VAL_LEN));3320goto out;3321}3322memcpy(&hostord, buf, sizeof(hostord));3323vallen = be32toh(hostord);3324buf += DICT_DATA_HDR_VAL_LEN;3325
3326if ((keylen < 0) || (vallen < 0)) {3327gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,3328"undersized length passed "3329"key:%d val:%d",3330keylen, vallen);3331goto out;3332}3333if ((buf + keylen) > (orig_buf + size)) {3334gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,3335"undersized buffer passed. "3336"available (%lu) < required (%lu)",3337(long)(orig_buf + size), (long)(buf + keylen));3338goto out;3339}3340key = buf;3341buf += keylen + 1; /* for '\0' */3342
3343if ((buf + vallen) > (orig_buf + size)) {3344gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,3345"undersized buffer passed. "3346"available (%lu) < required (%lu)",3347(long)(orig_buf + size), (long)(buf + vallen));3348goto out;3349}3350value = get_new_data();3351
3352if (!value) {3353ret = -1;3354goto out;3355}3356value->len = vallen;3357value->data = gf_memdup(buf, vallen);3358value->data_type = GF_DATA_TYPE_STR_OLD;3359value->is_static = _gf_false;3360buf += vallen;3361
3362ret = dict_addn(*fill, key, keylen, value);3363if (ret < 0) {3364data_destroy(value);3365goto out;3366}3367for (j = 0; j < totkeycount; j++) {3368if (keylen > keylenarr[j]) {3369if (!strcmp(key + keylen - keylenarr[j], suffix_key_arr[j])) {3370ret = dict_addn(*specific_dict, key, keylen, value);3371break;3372}3373}3374}3375
3376if (ret < 0)3377goto out;3378}3379
3380ret = 0;3381out:3382return ret;3383}
3384