glusterfs

Форк
0
3383 строки · 77.1 Кб
1
/*
2
  Copyright (c) 2008-2012 Red Hat, Inc. <http://www.redhat.com>
3
  This file is part of GlusterFS.
4

5
  This file is licensed to you under your choice of the GNU Lesser
6
  General Public License, version 3 or any later version (LGPLv3 or
7
  later), or the GNU General Public License, version 2 (GPLv2), in all
8
  cases 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

25
struct dict_cmp {
26
    dict_t *dict;
27
    gf_boolean_t (*value_ignore)(char *k);
28
};
29

30
#define VALIDATE_DATA_AND_LOG(data, type, key, ret_val)                        \
31
    do {                                                                       \
32
        if (!data || !data->data) {                                            \
33
            gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \
34
                             "data is NULL");                                  \
35
            return ret_val;                                                    \
36
        }                                                                      \
37
        /* Not of the asked type, or old version */                            \
38
        if ((data->data_type != type) &&                                       \
39
            (data->data_type != GF_DATA_TYPE_STR_OLD)) {                       \
40
            gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG, \
41
                             "key %s, %s type asked, has %s type", key,        \
42
                             data_type_name[type],                             \
43
                             data_type_name[data->data_type]);                 \
44
        }                                                                      \
45
    } while (0)
46

47
static data_t *
48
get_new_data(void)
49
{
50
    data_t *data = NULL;
51

52
    if (global_ctx) {
53
        data = mem_get(global_ctx->dict_data_pool);
54
    } else {
55
        data = mem_get(THIS->ctx->dict_data_pool);
56
    }
57

58
    if (!data)
59
        return NULL;
60

61
    GF_ATOMIC_INIT(data->refcount, 0);
62
    data->is_static = _gf_false;
63

64
    return data;
65
}
66

67
static dict_t *
68
get_new_dict_full(void)
69
{
70
    dict_t *dict = mem_get0(THIS->ctx->dict_pool);
71

72
    if (!dict) {
73
        return NULL;
74
    }
75

76
    dict->totkvlen = 0;
77
    LOCK_INIT(&dict->lock);
78

79
    return dict;
80
}
81

82
dict_t *
83
dict_new(void)
84
{
85
    dict_t *dict = get_new_dict_full();
86

87
    if (dict)
88
        dict_ref(dict);
89

90
    return dict;
91
}
92

93
int32_t
94
is_data_equal(data_t *one, data_t *two)
95
{
96
    struct iatt *iatt1, *iatt2;
97
    struct mdata_iatt *mdata_iatt1, *mdata_iatt2;
98

99
    if (!one || !two || !one->data || !two->data) {
100
        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
101
                         "input arguments are provided "
102
                         "with value data_t as NULL");
103
        return -1;
104
    }
105

106
    if (one == two)
107
        return 1;
108

109
    if (one->data == two->data)
110
        return 1;
111

112
    if (one->data_type != two->data_type) {
113
        return 0;
114
    }
115

116
    if (one->data_type == GF_DATA_TYPE_IATT) {
117
        if ((one->len < sizeof(struct iatt)) ||
118
            (two->len < sizeof(struct iatt))) {
119
            return 0;
120
        }
121

122
        iatt1 = (struct iatt *)one->data;
123
        iatt2 = (struct iatt *)two->data;
124

125
        /* Two iatt structs are considered equal if main fields are
126
         * equal, even if times differ.
127
         * TODO: maybe when ctime if fully operational we could
128
         *       enforce time matching. */
129
        if (iatt1->ia_ino != iatt2->ia_ino) {
130
            return 0;
131
        }
132
        if (iatt1->ia_type != iatt2->ia_type) {
133
            return 0;
134
        }
135
        if ((iatt1->ia_type == IA_IFBLK) || (iatt1->ia_type == IA_IFCHR)) {
136
            if (iatt1->ia_rdev != iatt2->ia_rdev) {
137
                return 0;
138
            }
139
        }
140
        if (gf_uuid_compare(iatt1->ia_gfid, iatt2->ia_gfid) != 0) {
141
            return 0;
142
        }
143

144
        /* TODO: ia_uid, ia_gid, ia_prot and ia_size can be changed
145
         *       with some commands. Here we don't have enough
146
         *       information to decide if they should match or not. */
147
        /*
148
                        if ((iatt1->ia_uid != iatt2->ia_uid) ||
149
                            (iatt1->ia_gid != iatt2->ia_gid) ||
150
                            (st_mode_from_ia(iatt1->ia_prot, iatt1->ia_type) !=
151
                                    st_mode_from_ia(iatt2->ia_prot,
152
           iatt2->ia_type))) { return 0;
153
                        }
154
                        if (iatt1->ia_type == IA_IFREG) {
155
                                if (iatt1->ia_size != iatt2->ia_size) {
156
                                        return 0;
157
                                }
158
                        }
159
        */
160
        return 1;
161
    }
162
    if (one->data_type == GF_DATA_TYPE_MDATA) {
163
        if ((one->len < sizeof(struct mdata_iatt)) ||
164
            (two->len < sizeof(struct mdata_iatt))) {
165
            return 0;
166
        }
167
        mdata_iatt1 = (struct mdata_iatt *)one->data;
168
        mdata_iatt2 = (struct mdata_iatt *)two->data;
169

170
        if (mdata_iatt1->ia_atime != mdata_iatt2->ia_atime ||
171
            mdata_iatt1->ia_mtime != mdata_iatt2->ia_mtime ||
172
            mdata_iatt1->ia_ctime != mdata_iatt2->ia_ctime ||
173
            mdata_iatt1->ia_atime_nsec != mdata_iatt2->ia_atime_nsec ||
174
            mdata_iatt1->ia_mtime_nsec != mdata_iatt2->ia_mtime_nsec ||
175
            mdata_iatt1->ia_ctime_nsec != mdata_iatt2->ia_ctime_nsec) {
176
            return 0;
177
        }
178
        return 1;
179
    }
180

181
    if (one->len != two->len)
182
        return 0;
183

184
    if (memcmp(one->data, two->data, one->len) == 0)
185
        return 1;
186

187
    return 0;
188
}
189

190
static int
191
key_value_cmp(dict_t *one, char *key1, data_t *value1, void *data)
192
{
193
    struct dict_cmp *cmp = data;
194
    dict_t *two = cmp->dict;
195
    data_t *value2 = dict_get(two, key1);
196

197
    if (value2) {
198
        if (cmp->value_ignore && cmp->value_ignore(key1))
199
            return 0;
200

201
        if (is_data_equal(value1, value2) == 1)
202
            return 0;
203
    }
204

205
    if (value2 == NULL) {
206
        gf_msg_debug(THIS->name, 0, "'%s' found only on one dict", key1);
207
    } else {
208
        gf_msg_debug(THIS->name, 0,
209
                     "'%s' is different in two dicts "
210
                     "(%u, %u)",
211
                     key1, value1->len, value2->len);
212
    }
213

214
    return -1;
215
}
216

217
static inline gf_boolean_t
218
dict_match_everything(dict_t *d, char *k, data_t *v, void *data)
219
{
220
    return _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
 */
230
gf_boolean_t
231
are_dicts_equal(dict_t *one, dict_t *two,
232
                gf_boolean_t (*match)(dict_t *d, char *k, data_t *v,
233
                                      void *data),
234
                void *match_data, gf_boolean_t (*value_ignore)(char *k))
235
{
236
    int num_matches1 = 0;
237
    int num_matches2 = 0;
238
    struct dict_cmp cmp = {0};
239

240
    if (one == two)
241
        return _gf_true;
242

243
    if (!match)
244
        match = dict_match_everything;
245

246
    if ((one == NULL) || (two == NULL)) {
247
        num_matches1 = dict_foreach_match(one ? one : two, match, NULL,
248
                                          dict_null_foreach_fn, NULL);
249
        goto done;
250
    }
251

252
    cmp.dict = two;
253
    cmp.value_ignore = value_ignore;
254
    num_matches1 = dict_foreach_match(one, match, match_data, key_value_cmp,
255
                                      &cmp);
256

257
    if (num_matches1 == -1)
258
        return _gf_false;
259

260
    if ((num_matches1 == one->count) && (one->count == two->count))
261
        return _gf_true;
262

263
    num_matches2 = dict_foreach_match(two, match, match_data,
264
                                      dict_null_foreach_fn, NULL);
265
done:
266
    /* If the number of matches is same in 'two' then for all the
267
     * 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' */
270
    if (num_matches1 == num_matches2)
271
        return _gf_true;
272
    return _gf_false;
273
}
274

275
static void
276
data_destroy(data_t *data)
277
{
278
    if (data) {
279
        if (!data->is_static)
280
            GF_FREE(data->data);
281

282
        data->len = 0xbabababa;
283
        mem_put(data);
284
    }
285
}
286

287
data_t *
288
data_copy(data_t *old)
289
{
290
    if (!old) {
291
        gf_msg_callingfn("dict", GF_LOG_WARNING, 0, LG_MSG_NULL_PTR,
292
                         "old is NULL");
293
        return NULL;
294
    }
295

296
    data_t *newdata = mem_get0(THIS->ctx->dict_data_pool);
297
    if (!newdata) {
298
        return NULL;
299
    }
300

301
    newdata->len = old->len;
302
    if (old->data) {
303
        newdata->data = gf_memdup(old->data, old->len);
304
        if (!newdata->data)
305
            goto err_out;
306
    }
307
    newdata->data_type = old->data_type;
308

309
    return newdata;
310

311
err_out:
312
    mem_put(newdata);
313

314
    return 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
 */
321
static data_pair_t *
322
dict_lookup_common(const dict_t *this, const char *key)
323
{
324
    data_pair_t *pair;
325

326
    for (pair = this->members_list; pair != NULL; pair = pair->next) {
327
        if (!strcmp(pair->key, key))
328
            return pair;
329
    }
330

331
    return NULL;
332
}
333

334
int32_t
335
dict_lookup(dict_t *this, char *key, data_t **data)
336
{
337
    if (!this || !key || !data) {
338
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
339
                         "!this || !key || "
340
                         "!data");
341
        return -1;
342
    }
343

344
    data_pair_t *tmp = NULL;
345

346
    LOCK(&this->lock);
347
    {
348
        tmp = dict_lookup_common(this, key);
349
    }
350
    UNLOCK(&this->lock);
351

352
    if (!tmp)
353
        return -1;
354

355
    *data = tmp->value;
356
    return 0;
357
}
358

359
static int32_t
360
dict_set_lk(dict_t *this, char *key, const int key_len, data_t *value,
361
            gf_boolean_t replace)
362
{
363
    data_pair_t *pair;
364

365
    /* Search for a existing key if 'replace' is asked for */
366
    if (replace) {
367
        pair = dict_lookup_common(this, key);
368
        if (pair) {
369
            data_t *unref_data = pair->value;
370
            pair->value = data_ref(value);
371
            this->totkvlen += (value->len - unref_data->len);
372
            data_unref(unref_data);
373
            /* Indicates duplicate key */
374
            return 0;
375
        }
376
    }
377

378
    pair = GF_MALLOC(sizeof(data_pair_t) + key_len + 1,
379
                     gf_common_mt_data_pair_t);
380
    if (caa_unlikely(!pair))
381
        return -1;
382

383
    pair->value = data_ref(value);
384
    memcpy(pair->key, key, key_len + 1);
385
    this->totkvlen += (key_len + 1 + value->len);
386

387
    pair->next = this->members_list;
388
    this->members_list = pair;
389
    this->count++;
390

391
    if (this->max_count < this->count)
392
        this->max_count = this->count;
393
    return 0;
394
}
395

396
int32_t
397
dict_setn(dict_t *this, char *key, const int keylen, data_t *value)
398
{
399
    int32_t ret;
400

401
    if (!this || !value) {
402
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
403
                         "!this || !value for "
404
                         "key=%s",
405
                         key);
406
        return -1;
407
    }
408

409
    LOCK(&this->lock);
410

411
    ret = dict_set_lk(this, key, keylen, value, 1);
412

413
    UNLOCK(&this->lock);
414

415
    return ret;
416
}
417

418
int32_t
419
dict_addn(dict_t *this, char *key, const int keylen, data_t *value)
420
{
421
    int32_t ret;
422

423
    if (!this || !value) {
424
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
425
                         "!this || !value for key=%s", key);
426
        return -1;
427
    }
428

429
    LOCK(&this->lock);
430

431
    ret = dict_set_lk(this, key, keylen, value, 0);
432

433
    UNLOCK(&this->lock);
434

435
    return ret;
436
}
437

438
data_t *
439
dict_get(dict_t *this, char *key)
440
{
441
    data_pair_t *pair;
442

443
    if (!this || !key) {
444
        gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,
445
                         "!this || key=%s", (key) ? key : "()");
446
        return NULL;
447
    }
448

449
    LOCK(&this->lock);
450
    {
451
        pair = dict_lookup_common(this, key);
452
    }
453
    UNLOCK(&this->lock);
454

455
    if (pair)
456
        return pair->value;
457

458
    return NULL;
459
}
460

461
int
462
dict_key_count(dict_t *this)
463
{
464
    int ret = -1;
465

466
    if (!this) {
467
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
468
                         "dict passed is NULL");
469
        return ret;
470
    }
471

472
    LOCK(&this->lock);
473
    {
474
        ret = this->count;
475
    }
476
    UNLOCK(&this->lock);
477

478
    return ret;
479
}
480

481
gf_boolean_t
482
dict_deln(dict_t *this, char *key, const int keylen)
483
{
484
    gf_boolean_t rc = _gf_false;
485

486
    if (!this || !key) {
487
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
488
                         "!this || key=%s", key);
489
        return rc;
490
    }
491

492
    LOCK(&this->lock);
493

494
    data_pair_t *pair = this->members_list;
495
    data_pair_t *prev = NULL;
496

497
    while (pair) {
498
        if (strcmp(pair->key, key) == 0) {
499
            this->totkvlen -= pair->value->len;
500
            data_unref(pair->value);
501

502
            if (prev)
503
                prev->next = pair->next;
504
            else
505
                this->members_list = pair->next;
506

507
            this->totkvlen -= (keylen + 1);
508
            GF_FREE(pair);
509
            this->count--;
510
            rc = _gf_true;
511
            break;
512
        }
513

514
        prev = pair;
515
        pair = pair->next;
516
    }
517

518
    UNLOCK(&this->lock);
519

520
    return rc;
521
}
522

523
/* removes and free all data_pair_t elements.
524
 * has to be called with this->lock held */
525
static void
526
dict_clear_data(dict_t *this)
527
{
528
    data_pair_t *curr = this->members_list;
529
    data_pair_t *next = NULL;
530

531
    while (curr != NULL) {
532
        next = curr->next;
533
        data_unref(curr->value);
534
        GF_FREE(curr);
535
        curr = next;
536
    }
537
    this->count = this->totkvlen = 0;
538
}
539

540
static void
541
dict_destroy(dict_t *this)
542
{
543
    if (!this) {
544
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
545
                         "dict is NULL");
546
        return;
547
    }
548

549
    glusterfs_ctx_t *ctx = NULL;
550
    uint64_t current_max = 0;
551
    uint32_t total_pairs = this->count;
552

553
    LOCK_DESTROY(&this->lock);
554

555
    dict_clear_data(this);
556

557
    free(this->extra_stdfree);
558

559
    /* update 'ctx->stats.dict.details' using max_count */
560
    ctx = 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 be
569
       broken by this, but a point to consider about ATOMIC macros. */
570
    current_max = GF_ATOMIC_GET(ctx->stats.max_dict_pairs);
571
    if (current_max < this->max_count)
572
        GF_ATOMIC_INIT(ctx->stats.max_dict_pairs, this->max_count);
573

574
    GF_ATOMIC_ADD(ctx->stats.total_pairs_used, total_pairs);
575
    GF_ATOMIC_INC(ctx->stats.total_dicts_used);
576

577
    mem_put(this);
578

579
    return;
580
}
581

582
void
583
dict_unref(dict_t *this)
584
{
585
    uint32_t ref = 0;
586

587
    if (!this) {
588
        gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,
589
                         "dict is NULL");
590
        return;
591
    }
592

593
    ref = GF_ATOMIC_DEC(this->refcount);
594

595
    if (!ref)
596
        dict_destroy(this);
597
}
598

599
dict_t *
600
dict_ref(dict_t *this)
601
{
602
    if (!this) {
603
        gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,
604
                         "dict is NULL");
605
        return NULL;
606
    }
607

608
    GF_ATOMIC_INC(this->refcount);
609
    return this;
610
}
611

612
void
613
data_unref(data_t *this)
614
{
615
    uint32_t ref;
616

617
    if (!this) {
618
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
619
                         "data is NULL");
620
        return;
621
    }
622

623
    ref = GF_ATOMIC_DEC(this->refcount);
624

625
    if (!ref)
626
        data_destroy(this);
627
}
628

629
data_t *
630
data_ref(data_t *this)
631
{
632
    if (!this) {
633
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
634
                         "data is NULL");
635
        return NULL;
636
    }
637

638
    GF_ATOMIC_INC(this->refcount);
639

640
    return this;
641
}
642

643
data_t *
644
data_from_int64(int64_t value)
645
{
646
    data_t *data = get_new_data();
647

648
    if (!data) {
649
        return NULL;
650
    }
651
    data->len = gf_asprintf(&data->data, "%" PRId64, value);
652
    if (-1 == data->len) {
653
        gf_msg_debug("dict", 0, "asprintf failed");
654
        data_destroy(data);
655
        return NULL;
656
    }
657
    data->len++; /* account for terminating NULL */
658
    data->data_type = GF_DATA_TYPE_INT;
659

660
    return data;
661
}
662

663
data_t *
664
data_from_int32(int32_t value)
665
{
666
    data_t *data = get_new_data();
667

668
    if (!data) {
669
        return NULL;
670
    }
671
    data->len = gf_asprintf(&data->data, "%" PRId32, value);
672
    if (-1 == data->len) {
673
        gf_msg_debug("dict", 0, "asprintf failed");
674
        data_destroy(data);
675
        return NULL;
676
    }
677

678
    data->len++; /* account for terminating NULL */
679
    data->data_type = GF_DATA_TYPE_INT;
680

681
    return data;
682
}
683

684
data_t *
685
data_from_int16(int16_t value)
686
{
687
    data_t *data = get_new_data();
688

689
    if (!data) {
690
        return NULL;
691
    }
692
    data->len = gf_asprintf(&data->data, "%" PRId16, value);
693
    if (-1 == data->len) {
694
        gf_msg_debug("dict", 0, "asprintf failed");
695
        data_destroy(data);
696
        return NULL;
697
    }
698

699
    data->len++; /* account for terminating NULL */
700
    data->data_type = GF_DATA_TYPE_INT;
701

702
    return data;
703
}
704

705
data_t *
706
data_from_int8(int8_t value)
707
{
708
    data_t *data = get_new_data();
709

710
    if (!data) {
711
        return NULL;
712
    }
713
    data->len = gf_asprintf(&data->data, "%d", value);
714
    if (-1 == data->len) {
715
        gf_msg_debug("dict", 0, "asprintf failed");
716
        data_destroy(data);
717
        return NULL;
718
    }
719

720
    data->len++; /* account for terminating NULL */
721
    data->data_type = GF_DATA_TYPE_INT;
722

723
    return data;
724
}
725

726
data_t *
727
data_from_uint64(uint64_t value)
728
{
729
    data_t *data = get_new_data();
730

731
    if (!data) {
732
        return NULL;
733
    }
734
    data->len = gf_asprintf(&data->data, "%" PRIu64, value);
735
    if (-1 == data->len) {
736
        gf_msg_debug("dict", 0, "asprintf failed");
737
        data_destroy(data);
738
        return NULL;
739
    }
740

741
    data->len++; /* account for terminating NULL */
742
    data->data_type = GF_DATA_TYPE_UINT;
743

744
    return data;
745
}
746

747
data_t *
748
data_from_double(double value)
749
{
750
    data_t *data = get_new_data();
751

752
    if (!data) {
753
        return NULL;
754
    }
755

756
    data->len = gf_asprintf(&data->data, "%f", value);
757
    if (data->len == -1) {
758
        gf_msg_debug("dict", 0, "asprintf failed");
759
        data_destroy(data);
760
        return NULL;
761
    }
762
    data->len++; /* account for terminating NULL */
763
    data->data_type = GF_DATA_TYPE_DOUBLE;
764

765
    return data;
766
}
767

768
data_t *
769
data_from_uint32(uint32_t value)
770
{
771
    data_t *data = get_new_data();
772

773
    if (!data) {
774
        return NULL;
775
    }
776
    data->len = gf_asprintf(&data->data, "%" PRIu32, value);
777
    if (-1 == data->len) {
778
        gf_msg_debug("dict", 0, "asprintf failed");
779
        data_destroy(data);
780
        return NULL;
781
    }
782

783
    data->len++; /* account for terminating NULL */
784
    data->data_type = GF_DATA_TYPE_UINT;
785

786
    return data;
787
}
788

789
data_t *
790
data_from_uint16(uint16_t value)
791
{
792
    data_t *data = get_new_data();
793

794
    if (!data) {
795
        return NULL;
796
    }
797
    data->len = gf_asprintf(&data->data, "%" PRIu16, value);
798
    if (-1 == data->len) {
799
        gf_msg_debug("dict", 0, "asprintf failed");
800
        data_destroy(data);
801
        return NULL;
802
    }
803

804
    data->len++; /* account for terminating NULL */
805
    data->data_type = GF_DATA_TYPE_UINT;
806

807
    return data;
808
}
809

810
static data_t *
811
data_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

815
    data_t *data = get_new_data();
816
    if (!data) {
817
        return NULL;
818
    }
819

820
    data->data = value;
821
    data->len = 0;
822
    data->is_static = is_static;
823

824
    data->data_type = GF_DATA_TYPE_PTR;
825
    return data;
826
}
827

828
data_t *
829
str_to_data(char *value)
830
{
831
    if (!value) {
832
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
833
                         "value is NULL");
834
        return NULL;
835
    }
836

837
    return strn_to_data(value, strlen(value));
838
}
839

840
data_t *
841
strn_to_data(char *value, const int vallen)
842
{
843
    if (!value) {
844
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
845
                         "value is NULL");
846
        return NULL;
847
    }
848
    data_t *data = get_new_data();
849

850
    if (!data) {
851
        return NULL;
852
    }
853
    data->len = vallen + 1;
854
    data->data_type = GF_DATA_TYPE_STR;
855

856
    data->data = value;
857
    data->is_static = _gf_true;
858

859
    return data;
860
}
861

862
static data_t *
863
data_from_dynstr(char *value)
864
{
865
    if (!value) {
866
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
867
                         "value is NULL");
868
        return NULL;
869
    }
870

871
    data_t *data = get_new_data();
872

873
    if (!data)
874
        return NULL;
875
    data->len = strlen(value) + 1;
876
    data->data = value;
877
    data->data_type = GF_DATA_TYPE_STR;
878

879
    return data;
880
}
881

882
data_t *
883
data_from_dynptr(void *value, int32_t len)
884
{
885
    data_t *data = get_new_data();
886

887
    if (!data)
888
        return NULL;
889

890
    data->len = len;
891
    data->data = value;
892
    data->data_type = GF_DATA_TYPE_PTR;
893

894
    return data;
895
}
896

897
data_t *
898
bin_to_data(void *value, int32_t len)
899
{
900
    if (!value) {
901
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
902
                         "value is NULL");
903
        return NULL;
904
    }
905

906
    data_t *data = get_new_data();
907

908
    if (!data)
909
        return NULL;
910

911
    data->is_static = _gf_true;
912
    data->len = len;
913
    data->data = value;
914

915
    return data;
916
}
917

918
static 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

931
int64_t
932
data_to_int64(data_t *data)
933
{
934
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);
935

936
    char *endptr = NULL;
937
    int64_t value = 0;
938

939
    errno = 0;
940
    value = strtoll(data->data, &endptr, 0);
941

942
    if (endptr && *endptr != '\0')
943
        /* Unrecognized characters at the end of string. */
944
        errno = EINVAL;
945
    if (errno) {
946
        gf_msg_callingfn("dict", GF_LOG_WARNING, errno,
947
                         LG_MSG_DATA_CONVERSION_ERROR,
948
                         "Error in data conversion: '%s' can't "
949
                         "be represented as int64_t",
950
                         data->data);
951
        return -1;
952
    }
953
    return value;
954
}
955

956
/* Like above but implies signed range check. */
957

958
#define DATA_TO_RANGED_SIGNED(endptr, value, data, type, min, max)             \
959
    do {                                                                       \
960
        errno = 0;                                                             \
961
        value = strtoll(data->data, &endptr, 0);                               \
962
        if (endptr && *endptr != '\0')                                         \
963
            errno = EINVAL;                                                    \
964
        if (errno || value > max || value < min) {                             \
965
            gf_msg_callingfn("dict", GF_LOG_WARNING, errno,                    \
966
                             LG_MSG_DATA_CONVERSION_ERROR,                     \
967
                             "Error in data conversion: '%s' can't "           \
968
                             "be represented as " #type,                       \
969
                             data->data);                                      \
970
            return -1;                                                         \
971
        }                                                                      \
972
        return (type)value;                                                    \
973
    } while (0)
974

975
int32_t
976
data_to_int32(data_t *data)
977
{
978
    char *endptr = NULL;
979
    int64_t value = 0;
980

981
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);
982
    DATA_TO_RANGED_SIGNED(endptr, value, data, int32_t, INT_MIN, INT_MAX);
983
}
984

985
int16_t
986
data_to_int16(data_t *data)
987
{
988
    char *endptr = NULL;
989
    int64_t value = 0;
990

991
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);
992
    DATA_TO_RANGED_SIGNED(endptr, value, data, int16_t, SHRT_MIN, SHRT_MAX);
993
}
994

995
int8_t
996
data_to_int8(data_t *data)
997
{
998
    char *endptr = NULL;
999
    int64_t value = 0;
1000

1001
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, "null", -1);
1002
    DATA_TO_RANGED_SIGNED(endptr, value, data, int8_t, CHAR_MIN, CHAR_MAX);
1003
}
1004

1005
uint64_t
1006
data_to_uint64(data_t *data)
1007
{
1008
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);
1009

1010
    char *endptr = NULL;
1011
    uint64_t value = 0;
1012

1013
    errno = 0;
1014
    value = strtoull(data->data, &endptr, 0);
1015

1016
    if (endptr && *endptr != '\0')
1017
        errno = EINVAL;
1018
    if (errno) {
1019
        gf_msg_callingfn("dict", GF_LOG_WARNING, errno,
1020
                         LG_MSG_DATA_CONVERSION_ERROR,
1021
                         "Error in data conversion: '%s' can't "
1022
                         "be represented as uint64_t",
1023
                         data->data);
1024
        return -1;
1025
    }
1026
    return value;
1027
}
1028

1029
/* Like above but implies unsigned range check. */
1030

1031
#define DATA_TO_RANGED_UNSIGNED(endptr, value, data, type, max)                \
1032
    do {                                                                       \
1033
        errno = 0;                                                             \
1034
        value = strtoull(data->data, &endptr, 0);                              \
1035
        if (endptr && *endptr != '\0')                                         \
1036
            errno = EINVAL;                                                    \
1037
        if (errno || value > max) {                                            \
1038
            gf_msg_callingfn("dict", GF_LOG_WARNING, errno,                    \
1039
                             LG_MSG_DATA_CONVERSION_ERROR,                     \
1040
                             "Error in data conversion: '%s' can't "           \
1041
                             "be represented as " #type,                       \
1042
                             data->data);                                      \
1043
            return -1;                                                         \
1044
        }                                                                      \
1045
        return (type)value;                                                    \
1046
    } while (0)
1047

1048
uint32_t
1049
data_to_uint32(data_t *data)
1050
{
1051
    char *endptr = NULL;
1052
    uint64_t value = 0;
1053

1054
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);
1055
    DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint32_t, UINT_MAX);
1056
}
1057

1058
uint16_t
1059
data_to_uint16(data_t *data)
1060
{
1061
    char *endptr = NULL;
1062
    uint64_t value = 0;
1063

1064
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);
1065
    DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint16_t, USHRT_MAX);
1066
}
1067

1068
uint8_t
1069
data_to_uint8(data_t *data)
1070
{
1071
    char *endptr = NULL;
1072
    uint64_t value = 0;
1073

1074
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, "null", -1);
1075
    DATA_TO_RANGED_UNSIGNED(endptr, value, data, uint8_t, UCHAR_MAX);
1076
}
1077

1078
char *
1079
data_to_str(data_t *data)
1080
{
1081
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, "null", NULL);
1082
    return data->data;
1083
}
1084

1085
void *
1086
data_to_ptr(data_t *data)
1087
{
1088
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL);
1089
    return data->data;
1090
}
1091

1092
void *
1093
data_to_bin(data_t *data)
1094
{
1095
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, "null", NULL);
1096
    return data->data;
1097
}
1098

1099
struct iatt *
1100
data_to_iatt(data_t *data, char *key)
1101
{
1102
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, NULL);
1103

1104
    /* We only check for smaller size. If it's bigger we simply ignore
1105
     * 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). */
1108
    if (data->len < sizeof(struct iatt)) {
1109
        gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF,
1110
                "key=%s", key, NULL);
1111
        return NULL;
1112
    }
1113

1114
    return (struct iatt *)data->data;
1115
}
1116

1117
int
1118
dict_null_foreach_fn(dict_t *d, char *k, data_t *v, void *tmp)
1119
{
1120
    return 0;
1121
}
1122

1123
int
1124
dict_remove_foreach_fn(dict_t *d, char *k, data_t *v, void *_tmp)
1125
{
1126
    if (!d || !k) {
1127
        gf_smsg("glusterfs", GF_LOG_WARNING, EINVAL, LG_MSG_KEY_OR_VALUE_NULL,
1128
                "d=%s", d ? "key" : "dictionary", NULL);
1129
        return -1;
1130
    }
1131

1132
    dict_del(d, k);
1133
    return 0;
1134
}
1135

1136
int
1137
dict_foreach(dict_t *dict,
1138
             int (*fn)(dict_t *this, char *key, data_t *value, void *data),
1139
             void *data)
1140
{
1141
    int ret = dict_foreach_match(dict, dict_match_everything, NULL, fn, data);
1142

1143
    if (ret > 0)
1144
        ret = 0;
1145

1146
    return ret;
1147
}
1148

1149
/* return values:
1150
   -1 = failure,
1151
    0 = no matches found,
1152
   +n = n number of matches
1153
*/
1154
int
1155
dict_foreach_match(dict_t *dict,
1156
                   gf_boolean_t (*match)(dict_t *this, char *key, data_t *value,
1157
                                         void *mdata),
1158
                   void *match_data,
1159
                   int (*action)(dict_t *this, char *key, data_t *value,
1160
                                 void *adata),
1161
                   void *action_data)
1162
{
1163
    if (!dict || !match || !action) {
1164
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1165
                         "dict|match|action is "
1166
                         "NULL");
1167
        return -1;
1168
    }
1169

1170
    int ret;
1171
    int count = 0;
1172
    data_pair_t *pairs = dict->members_list;
1173
    data_pair_t *next = NULL;
1174

1175
    while (pairs) {
1176
        next = pairs->next;
1177
        if (match(dict, pairs->key, pairs->value, match_data)) {
1178
            ret = action(dict, pairs->key, pairs->value, action_data);
1179
            if (ret < 0)
1180
                return ret;
1181
            count++;
1182
        }
1183
        pairs = next;
1184
    }
1185

1186
    return count;
1187
}
1188

1189
static gf_boolean_t
1190
dict_fnmatch(dict_t *d, char *k, data_t *val, void *match_data)
1191
{
1192
    return (fnmatch(match_data, k, 0) == 0);
1193
}
1194
/* return values:
1195
   -1 = failure,
1196
    0 = no matches found,
1197
   +n = n number of matches
1198
*/
1199
int
1200
dict_foreach_fnmatch(dict_t *dict, char *pattern,
1201
                     int (*fn)(dict_t *this, char *key, data_t *value,
1202
                               void *data),
1203
                     void *data)
1204
{
1205
    return 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

1221
int
1222
dict_keys_join(void *value, int size, dict_t *dict, int (*filter_fn)(char *k))
1223
{
1224
    int len = 0;
1225
    data_pair_t *pairs = dict->members_list;
1226
    data_pair_t *next = NULL;
1227

1228
    while (pairs) {
1229
        next = pairs->next;
1230

1231
        if (filter_fn && filter_fn(pairs->key)) {
1232
            pairs = next;
1233
            continue;
1234
        }
1235

1236
        if (value && (size > len))
1237
            strncpy(value + len, pairs->key, size - len);
1238

1239
        len += (strlen(pairs->key) + 1);
1240

1241
        pairs = next;
1242
    }
1243

1244
    return len;
1245
}
1246

1247
static int
1248
dict_copy_one(dict_t *unused, char *key, data_t *value, void *newdict)
1249
{
1250
    return dict_set((dict_t *)newdict, key, (value));
1251
}
1252

1253
dict_t *
1254
dict_copy(dict_t *dict, dict_t *new)
1255
{
1256
    if (!dict) {
1257
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1258
                         "dict is NULL");
1259
        return NULL;
1260
    }
1261

1262
    if (!new)
1263
        new = get_new_dict_full();
1264

1265
    dict_foreach(dict, dict_copy_one, new);
1266

1267
    return new;
1268
}
1269

1270
int
1271
dict_reset(dict_t *dict)
1272
{
1273
    int32_t ret = -1;
1274
    if (!dict) {
1275
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1276
                         "dict is NULL");
1277
        goto out;
1278
    }
1279

1280
    LOCK(&dict->lock);
1281

1282
    dict_clear_data(dict);
1283
    dict->members_list = NULL;
1284

1285
    UNLOCK(&dict->lock);
1286
    ret = 0;
1287
out:
1288
    return ret;
1289
}
1290

1291
dict_t *
1292
dict_copy_with_ref(dict_t *dict, dict_t *new)
1293
{
1294
    dict_t *local_new = NULL;
1295

1296
    GF_VALIDATE_OR_GOTO("dict", dict, fail);
1297

1298
    if (new == NULL) {
1299
        local_new = dict_new();
1300
        GF_VALIDATE_OR_GOTO("dict", local_new, fail);
1301
        new = local_new;
1302
    }
1303

1304
    dict_foreach(dict, dict_copy_one, new);
1305
fail:
1306
    return 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

1320
static int
1321
dict_get_with_refn(dict_t *this, char *key, data_t **data)
1322
{
1323
    data_pair_t *pair = NULL;
1324
    int ret = -ENOENT;
1325

1326
    LOCK(&this->lock);
1327
    {
1328
        pair = dict_lookup_common(this, key);
1329

1330
        if (pair) {
1331
            ret = 0;
1332
            *data = data_ref(pair->value);
1333
        }
1334
    }
1335
    UNLOCK(&this->lock);
1336

1337
    return ret;
1338
}
1339

1340
int
1341
dict_get_with_ref(dict_t *this, char *key, data_t **data)
1342
{
1343
    if (caa_unlikely(!this)) {
1344
        /* There are possibilities where dict can be NULL. so not so critical
1345
         * for users to know */
1346
        gf_msg_callingfn("dict", GF_LOG_DEBUG, EINVAL, LG_MSG_INVALID_ARG,
1347
                         "dict is NULL: %s", key);
1348
        return -EINVAL;
1349
    }
1350
    if (caa_unlikely(!key || !data)) {
1351
        /* is there a chance like this? then it can be a coding error, but in
1352
         * any case, this should be caught early, so good to log it out. */
1353
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1354
                         "key (%s) or data ptr is NULL", key);
1355

1356
        return -EINVAL;
1357
    }
1358
    return dict_get_with_refn(this, key, data);
1359
}
1360

1361
static int
1362
data_to_ptr_common(data_t *data, void **val)
1363
{
1364
    int ret = 0;
1365

1366
    if (!data) {
1367
        ret = -EINVAL;
1368
        goto err;
1369
    }
1370

1371
    *val = data->data;
1372
err:
1373
    return ret;
1374
}
1375

1376
static int
1377
data_to_int8_ptr(data_t *data, int8_t *val)
1378
{
1379
    int ret = 0;
1380

1381
    if (!data || !val) {
1382
        ret = -EINVAL;
1383
        goto err;
1384
    }
1385

1386
    errno = 0;
1387
    *val = strtol(data->data, NULL, 0);
1388
    if (errno != 0)
1389
        ret = -errno;
1390

1391
err:
1392
    return ret;
1393
}
1394

1395
static int
1396
data_to_int16_ptr(data_t *data, int16_t *val)
1397
{
1398
    int ret = 0;
1399

1400
    if (!data || !val) {
1401
        ret = -EINVAL;
1402
        goto err;
1403
    }
1404

1405
    errno = 0;
1406
    *val = strtol(data->data, NULL, 0);
1407
    if (errno != 0)
1408
        ret = -errno;
1409

1410
err:
1411
    return ret;
1412
}
1413

1414
static int
1415
data_to_int32_ptr(data_t *data, int32_t *val)
1416
{
1417
    int ret = 0;
1418

1419
    if (!data || !val) {
1420
        ret = -EINVAL;
1421
        goto err;
1422
    }
1423

1424
    errno = 0;
1425
    *val = strtol(data->data, NULL, 0);
1426
    if (errno != 0)
1427
        ret = -errno;
1428

1429
err:
1430
    return ret;
1431
}
1432

1433
static int
1434
data_to_int64_ptr(data_t *data, int64_t *val)
1435
{
1436
    int ret = 0;
1437

1438
    if (!data || !val) {
1439
        ret = -EINVAL;
1440
        goto err;
1441
    }
1442

1443
    errno = 0;
1444
    *val = strtoll(data->data, NULL, 0);
1445
    if (errno != 0)
1446
        ret = -errno;
1447

1448
err:
1449
    return ret;
1450
}
1451

1452
static int
1453
data_to_uint16_ptr(data_t *data, uint16_t *val)
1454
{
1455
    int ret = 0;
1456

1457
    if (!data || !val) {
1458
        ret = -EINVAL;
1459
        goto err;
1460
    }
1461

1462
    errno = 0;
1463
    *val = strtoul(data->data, NULL, 0);
1464
    if (errno != 0)
1465
        ret = -errno;
1466

1467
err:
1468
    return ret;
1469
}
1470

1471
static int
1472
data_to_uint32_ptr(data_t *data, uint32_t *val)
1473
{
1474
    int ret = 0;
1475

1476
    if (!data || !val) {
1477
        ret = -EINVAL;
1478
        goto err;
1479
    }
1480

1481
    errno = 0;
1482
    *val = strtoul(data->data, NULL, 0);
1483
    if (errno != 0)
1484
        ret = -errno;
1485

1486
err:
1487
    return ret;
1488
}
1489

1490
static int
1491
data_to_uint64_ptr(data_t *data, uint64_t *val)
1492
{
1493
    int ret = 0;
1494

1495
    if (!data || !val) {
1496
        ret = -EINVAL;
1497
        goto err;
1498
    }
1499

1500
    errno = 0;
1501
    *val = strtoull(data->data, NULL, 0);
1502
    if (errno != 0)
1503
        ret = -errno;
1504

1505
err:
1506
    return ret;
1507
}
1508

1509
static int
1510
data_to_double_ptr(data_t *data, double *val)
1511
{
1512
    int ret = 0;
1513

1514
    if (!data || !val) {
1515
        ret = -EINVAL;
1516
        goto err;
1517
    }
1518

1519
    errno = 0;
1520
    *val = strtod(data->data, NULL);
1521
    if (errno != 0)
1522
        ret = -errno;
1523

1524
err:
1525
    return ret;
1526
}
1527

1528
int
1529
dict_get_int8(dict_t *this, char *key, int8_t *val)
1530
{
1531
    data_t *data = NULL;
1532
    int ret = 0;
1533

1534
    if (!val) {
1535
        ret = -EINVAL;
1536
        goto err;
1537
    }
1538

1539
    ret = dict_get_with_ref(this, key, &data);
1540
    if (ret != 0) {
1541
        goto err;
1542
    }
1543

1544
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);
1545

1546
    ret = data_to_int8_ptr(data, val);
1547

1548
err:
1549
    if (data)
1550
        data_unref(data);
1551
    return ret;
1552
}
1553

1554
int
1555
dict_set_int8(dict_t *this, char *key, int8_t val)
1556
{
1557
    data_t *data = NULL;
1558
    int ret = 0;
1559

1560
    data = data_from_int8(val);
1561
    if (!data) {
1562
        ret = -EINVAL;
1563
        goto err;
1564
    }
1565

1566
    ret = dict_set(this, key, data);
1567
    if (ret < 0)
1568
        data_destroy(data);
1569

1570
err:
1571
    return ret;
1572
}
1573

1574
int
1575
dict_get_int16(dict_t *this, char *key, int16_t *val)
1576
{
1577
    data_t *data = NULL;
1578
    int ret = 0;
1579

1580
    if (!val) {
1581
        ret = -EINVAL;
1582
        goto err;
1583
    }
1584

1585
    ret = dict_get_with_ref(this, key, &data);
1586
    if (ret != 0) {
1587
        goto err;
1588
    }
1589

1590
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);
1591

1592
    ret = data_to_int16_ptr(data, val);
1593

1594
err:
1595
    if (data)
1596
        data_unref(data);
1597
    return ret;
1598
}
1599

1600
int
1601
dict_set_int16(dict_t *this, char *key, int16_t val)
1602
{
1603
    data_t *data = NULL;
1604
    int ret = 0;
1605

1606
    data = data_from_int16(val);
1607
    if (!data) {
1608
        ret = -EINVAL;
1609
        goto err;
1610
    }
1611

1612
    ret = dict_set(this, key, data);
1613
    if (ret < 0)
1614
        data_destroy(data);
1615

1616
err:
1617
    return ret;
1618
}
1619

1620
int
1621
dict_get_int32n(dict_t *this, char *key, const int keylen, int32_t *val)
1622
{
1623
    data_t *data = NULL;
1624
    int ret = 0;
1625

1626
    if (!this || !key || !val) {
1627
        ret = -EINVAL;
1628
        goto err;
1629
    }
1630

1631
    ret = dict_get_with_refn(this, key, &data);
1632
    if (ret != 0) {
1633
        goto err;
1634
    }
1635

1636
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);
1637

1638
    ret = data_to_int32_ptr(data, val);
1639

1640
err:
1641
    if (data)
1642
        data_unref(data);
1643
    return ret;
1644
}
1645

1646
int
1647
dict_get_int32(dict_t *this, char *key, int32_t *val)
1648
{
1649
    data_t *data = NULL;
1650
    int ret = 0;
1651

1652
    if (!val) {
1653
        ret = -EINVAL;
1654
        goto err;
1655
    }
1656

1657
    ret = dict_get_with_ref(this, key, &data);
1658
    if (ret != 0) {
1659
        goto err;
1660
    }
1661

1662
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);
1663

1664
    ret = data_to_int32_ptr(data, val);
1665

1666
err:
1667
    if (data)
1668
        data_unref(data);
1669
    return ret;
1670
}
1671

1672
int
1673
dict_set_int32n(dict_t *this, char *key, const int keylen, int32_t val)
1674
{
1675
    data_t *data = NULL;
1676
    int ret = 0;
1677

1678
    data = data_from_int32(val);
1679
    if (!data) {
1680
        ret = -EINVAL;
1681
        goto err;
1682
    }
1683

1684
    ret = dict_setn(this, key, keylen, data);
1685
    if (ret < 0)
1686
        data_destroy(data);
1687

1688
err:
1689
    return ret;
1690
}
1691

1692
int
1693
dict_set_int32(dict_t *this, char *key, int32_t val)
1694
{
1695
    data_t *data = data_from_int32(val);
1696
    int ret = 0;
1697

1698
    if (!data) {
1699
        ret = -EINVAL;
1700
        goto err;
1701
    }
1702

1703
    ret = dict_set(this, key, data);
1704
    if (ret < 0)
1705
        data_destroy(data);
1706

1707
err:
1708
    return ret;
1709
}
1710

1711
int
1712
dict_get_int64(dict_t *this, char *key, int64_t *val)
1713
{
1714
    data_t *data = NULL;
1715
    int ret = 0;
1716

1717
    if (!val) {
1718
        ret = -EINVAL;
1719
        goto err;
1720
    }
1721

1722
    ret = dict_get_with_ref(this, key, &data);
1723
    if (ret != 0) {
1724
        goto err;
1725
    }
1726

1727
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);
1728

1729
    ret = data_to_int64_ptr(data, val);
1730

1731
err:
1732
    if (data)
1733
        data_unref(data);
1734
    return ret;
1735
}
1736

1737
int
1738
dict_set_int64(dict_t *this, char *key, int64_t val)
1739
{
1740
    data_t *data = data_from_int64(val);
1741
    int ret = 0;
1742

1743
    if (!data) {
1744
        ret = -EINVAL;
1745
        goto err;
1746
    }
1747

1748
    ret = dict_set(this, key, data);
1749
    if (ret < 0)
1750
        data_destroy(data);
1751

1752
err:
1753
    return ret;
1754
}
1755

1756
int
1757
dict_get_int64n(dict_t *this, char *key, const int keylen, int64_t *val)
1758
{
1759
    data_t *data = NULL;
1760
    int ret = 0;
1761

1762
    if (!this || !key || !val) {
1763
        ret = -EINVAL;
1764
        goto err;
1765
    }
1766

1767
    ret = dict_get_with_refn(this, key, &data);
1768
    if (ret != 0) {
1769
        goto err;
1770
    }
1771

1772
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);
1773

1774
    ret = data_to_int64_ptr(data, val);
1775

1776
err:
1777
    if (data)
1778
        data_unref(data);
1779
    return ret;
1780
}
1781

1782
int
1783
dict_set_int64n(dict_t *this, char *key, const int keylen, int64_t val)
1784
{
1785
    data_t *data = data_from_int64(val);
1786
    int ret = 0;
1787

1788
    if (!data) {
1789
        ret = -EINVAL;
1790
        goto err;
1791
    }
1792

1793
    ret = dict_setn(this, key, keylen, data);
1794
    if (ret < 0)
1795
        data_destroy(data);
1796

1797
err:
1798
    return ret;
1799
}
1800

1801
int
1802
dict_get_uint16(dict_t *this, char *key, uint16_t *val)
1803
{
1804
    data_t *data = NULL;
1805
    int ret = 0;
1806

1807
    if (!val) {
1808
        ret = -EINVAL;
1809
        goto err;
1810
    }
1811

1812
    ret = dict_get_with_ref(this, key, &data);
1813
    if (ret != 0) {
1814
        goto err;
1815
    }
1816

1817
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL);
1818

1819
    ret = data_to_uint16_ptr(data, val);
1820

1821
err:
1822
    if (data)
1823
        data_unref(data);
1824
    return ret;
1825
}
1826

1827
int
1828
dict_set_uint16(dict_t *this, char *key, uint16_t val)
1829
{
1830
    data_t *data = data_from_uint16(val);
1831
    int ret = 0;
1832

1833
    if (!data) {
1834
        ret = -EINVAL;
1835
        goto err;
1836
    }
1837

1838
    ret = dict_set(this, key, data);
1839
    if (ret < 0)
1840
        data_destroy(data);
1841

1842
err:
1843
    return ret;
1844
}
1845

1846
int
1847
dict_get_uint32(dict_t *this, char *key, uint32_t *val)
1848
{
1849
    data_t *data = NULL;
1850
    int ret = 0;
1851

1852
    if (!val) {
1853
        ret = -EINVAL;
1854
        goto err;
1855
    }
1856

1857
    ret = dict_get_with_ref(this, key, &data);
1858
    if (ret != 0) {
1859
        goto err;
1860
    }
1861

1862
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL);
1863

1864
    ret = data_to_uint32_ptr(data, val);
1865

1866
err:
1867
    if (data)
1868
        data_unref(data);
1869
    return ret;
1870
}
1871

1872
int
1873
dict_set_uint32(dict_t *this, char *key, uint32_t val)
1874
{
1875
    data_t *data = data_from_uint32(val);
1876
    int ret = 0;
1877

1878
    if (!data) {
1879
        ret = -EINVAL;
1880
        goto err;
1881
    }
1882

1883
    ret = dict_set(this, key, data);
1884
    if (ret < 0)
1885
        data_destroy(data);
1886

1887
err:
1888
    return ret;
1889
}
1890

1891
int
1892
dict_get_uint64(dict_t *this, char *key, uint64_t *val)
1893
{
1894
    data_t *data = NULL;
1895
    int ret = 0;
1896

1897
    if (!val) {
1898
        ret = -EINVAL;
1899
        goto err;
1900
    }
1901

1902
    ret = dict_get_with_ref(this, key, &data);
1903
    if (ret != 0) {
1904
        goto err;
1905
    }
1906

1907
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_UINT, key, -EINVAL);
1908

1909
    ret = data_to_uint64_ptr(data, val);
1910

1911
err:
1912
    if (data)
1913
        data_unref(data);
1914
    return ret;
1915
}
1916

1917
int
1918
dict_set_uint64(dict_t *this, char *key, uint64_t val)
1919
{
1920
    data_t *data = data_from_uint64(val);
1921
    int ret = 0;
1922

1923
    if (!data) {
1924
        ret = -EINVAL;
1925
        goto err;
1926
    }
1927

1928
    ret = dict_set(this, key, data);
1929
    if (ret < 0)
1930
        data_destroy(data);
1931

1932
err:
1933
    return 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
 */
1945
int
1946
dict_check_flag(dict_t *this, char *key, int flag)
1947
{
1948
    data_t *data = NULL;
1949
    int ret = -ENOENT;
1950

1951
    ret = dict_get_with_ref(this, key, &data);
1952
    if (ret < 0) {
1953
        return ret;
1954
    }
1955

1956
    if (BIT_VALUE((unsigned char *)(data->data), flag))
1957
        ret = 1;
1958
    else
1959
        ret = 0;
1960

1961
    data_unref(data);
1962
    return 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
 */
1970
static int
1971
_dict_modify_flag(dict_t *this, char *key, int flag, int op)
1972
{
1973
    data_t *data = NULL;
1974
    int ret = 0;
1975
    data_pair_t *pair = NULL;
1976
    char *ptr = NULL;
1977
    size_t keylen;
1978

1979
    if (!this || !key) {
1980
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
1981
                         "dict OR key (%s) is NULL", key);
1982
        ret = -EINVAL;
1983
        goto 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
     */
1990
    GF_ASSERT(flag >= 0 && flag < DICT_MAX_FLAGS);
1991

1992
    LOCK(&this->lock);
1993
    {
1994
        pair = dict_lookup_common(this, key);
1995

1996
        if (pair) {
1997
            data = pair->value;
1998
            if (op == DICT_FLAG_SET)
1999
                BIT_SET((unsigned char *)(data->data), flag);
2000
            else
2001
                BIT_CLEAR((unsigned char *)(data->data), flag);
2002
        } else {
2003
            ptr = GF_CALLOC(1, DICT_MAX_FLAGS / 8, gf_common_mt_char);
2004
            if (!ptr) {
2005
                gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY,
2006
                        "flag bit array", NULL);
2007
                ret = -ENOMEM;
2008
                goto err;
2009
            }
2010

2011
            data = data_from_dynptr(ptr, DICT_MAX_FLAGS / 8);
2012

2013
            if (!data) {
2014
                gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY, "data",
2015
                        NULL);
2016
                GF_FREE(ptr);
2017
                ret = -ENOMEM;
2018
                goto err;
2019
            }
2020

2021
            if (op == DICT_FLAG_SET)
2022
                BIT_SET((unsigned char *)(data->data), flag);
2023
            else
2024
                BIT_CLEAR((unsigned char *)(data->data), flag);
2025

2026
            keylen = strlen(key) + 1;  // including terminating NULL char
2027
            pair = GF_MALLOC(sizeof(data_pair_t) + keylen,
2028
                             gf_common_mt_data_pair_t);
2029
            if (caa_unlikely(!pair)) {
2030
                gf_smsg("dict", GF_LOG_ERROR, ENOMEM, LG_MSG_NO_MEMORY,
2031
                        "dict pair", NULL);
2032
                ret = -ENOMEM;
2033
                goto err;
2034
            }
2035

2036
            pair->value = data_ref(data);
2037
            memcpy(pair->key, key, keylen);
2038
            this->totkvlen += (keylen + data->len);
2039

2040
            pair->next = this->members_list;
2041
            this->members_list = pair;
2042
            this->count++;
2043

2044
            if (this->max_count < this->count)
2045
                this->max_count = this->count;
2046
        }
2047
    }
2048

2049
    UNLOCK(&this->lock);
2050
    return 0;
2051

2052
err:
2053
    if (key && this)
2054
        UNLOCK(&this->lock);
2055

2056
    if (pair)
2057
        GF_FREE(pair);
2058

2059
    if (data)
2060
        data_destroy(data);
2061

2062
    gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_DICT_SET_FAILED, "key=%s", key,
2063
            NULL);
2064

2065
    return 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

2077
int
2078
dict_set_flag(dict_t *this, char *key, int flag)
2079
{
2080
    return _dict_modify_flag(this, key, flag, DICT_FLAG_SET);
2081
}
2082

2083
int
2084
dict_clear_flag(dict_t *this, char *key, int flag)
2085
{
2086
    return _dict_modify_flag(this, key, flag, DICT_FLAG_CLEAR);
2087
}
2088

2089
int
2090
dict_get_double(dict_t *this, char *key, double *val)
2091
{
2092
    data_t *data = NULL;
2093
    int ret = 0;
2094

2095
    if (!val) {
2096
        ret = -EINVAL;
2097
        goto err;
2098
    }
2099

2100
    ret = dict_get_with_ref(this, key, &data);
2101
    if (ret != 0) {
2102
        goto err;
2103
    }
2104

2105
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_DOUBLE, key, -EINVAL);
2106

2107
    ret = data_to_double_ptr(data, val);
2108

2109
err:
2110
    if (data)
2111
        data_unref(data);
2112
    return ret;
2113
}
2114

2115
int
2116
dict_set_double(dict_t *this, char *key, double val)
2117
{
2118
    data_t *data = data_from_double(val);
2119
    int ret = 0;
2120

2121
    if (!data) {
2122
        ret = -EINVAL;
2123
        goto err;
2124
    }
2125

2126
    ret = dict_set(this, key, data);
2127
    if (ret < 0)
2128
        data_destroy(data);
2129

2130
err:
2131
    return ret;
2132
}
2133

2134
int
2135
dict_set_static_ptr(dict_t *this, char *key, void *ptr)
2136
{
2137
    data_t *data = data_from_ptr_common(ptr, _gf_true);
2138
    int ret = 0;
2139

2140
    if (!data) {
2141
        ret = -EINVAL;
2142
        goto err;
2143
    }
2144

2145
    ret = dict_set(this, key, data);
2146
    if (ret < 0)
2147
        data_destroy(data);
2148

2149
err:
2150
    return ret;
2151
}
2152

2153
int
2154
dict_set_dynptr(dict_t *this, char *key, void *ptr, size_t len)
2155
{
2156
    data_t *data = data_from_dynptr(ptr, len);
2157
    int ret = 0;
2158

2159
    if (!data) {
2160
        ret = -EINVAL;
2161
        goto err;
2162
    }
2163

2164
    ret = dict_set(this, key, data);
2165
    if (ret < 0)
2166
        data_destroy(data);
2167

2168
err:
2169
    return ret;
2170
}
2171

2172
int
2173
dict_get_ptr(dict_t *this, char *key, void **ptr)
2174
{
2175
    data_t *data = NULL;
2176
    int ret = 0;
2177

2178
    if (!ptr) {
2179
        ret = -EINVAL;
2180
        goto err;
2181
    }
2182

2183
    ret = dict_get_with_ref(this, key, &data);
2184
    if (ret != 0) {
2185
        goto err;
2186
    }
2187

2188
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL);
2189

2190
    ret = data_to_ptr_common(data, ptr);
2191
    if (ret != 0) {
2192
        goto err;
2193
    }
2194

2195
err:
2196
    if (data)
2197
        data_unref(data);
2198

2199
    return ret;
2200
}
2201

2202
int
2203
dict_get_ptr_and_len(dict_t *this, char *key, void **ptr, int *len)
2204
{
2205
    data_t *data = NULL;
2206
    int ret = 0;
2207

2208
    if (!ptr) {
2209
        ret = -EINVAL;
2210
        goto err;
2211
    }
2212

2213
    ret = dict_get_with_ref(this, key, &data);
2214
    if (ret != 0) {
2215
        goto err;
2216
    }
2217

2218
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, -EINVAL);
2219

2220
    *len = data->len;
2221

2222
    ret = data_to_ptr_common(data, ptr);
2223
    if (ret != 0) {
2224
        goto err;
2225
    }
2226

2227
err:
2228
    if (data)
2229
        data_unref(data);
2230

2231
    return ret;
2232
}
2233

2234
/* Get string - with known key length */
2235
int
2236
dict_get_strn(dict_t *this, char *key, const int keylen, char **str)
2237
{
2238
    data_t *data = NULL;
2239
    int ret = -EINVAL;
2240

2241
    if (!this || !key || !str) {
2242
        goto err;
2243
    }
2244
    ret = dict_get_with_refn(this, key, &data);
2245
    if (ret < 0) {
2246
        goto err;
2247
    }
2248

2249
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL);
2250

2251
    *str = data->data;
2252

2253
err:
2254
    if (data)
2255
        data_unref(data);
2256

2257
    return ret;
2258
}
2259

2260
int
2261
dict_get_str(dict_t *this, char *key, char **str)
2262
{
2263
    data_t *data = NULL;
2264
    int ret = -EINVAL;
2265

2266
    if (!str) {
2267
        goto err;
2268
    }
2269
    ret = dict_get_with_ref(this, key, &data);
2270
    if (ret < 0) {
2271
        goto err;
2272
    }
2273

2274
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_STR, key, -EINVAL);
2275

2276
    *str = data->data;
2277

2278
err:
2279
    if (data)
2280
        data_unref(data);
2281

2282
    return ret;
2283
}
2284

2285
int
2286
dict_set_str(dict_t *this, char *key, char *str)
2287
{
2288
    data_t *data = str_to_data(str);
2289
    int ret = 0;
2290

2291
    if (!data) {
2292
        ret = -EINVAL;
2293
        goto err;
2294
    }
2295

2296
    ret = dict_set(this, key, data);
2297
    if (ret < 0)
2298
        data_destroy(data);
2299

2300
err:
2301
    return ret;
2302
}
2303

2304
/* Set string - with known key length */
2305
int
2306
dict_set_strn(dict_t *this, char *key, const int keylen, char *str)
2307
{
2308
    data_t *data = NULL;
2309
    int ret = 0;
2310

2311
    data = str_to_data(str);
2312
    if (!data) {
2313
        ret = -EINVAL;
2314
        goto err;
2315
    }
2316

2317
    ret = dict_setn(this, key, keylen, data);
2318
    if (ret < 0)
2319
        data_destroy(data);
2320

2321
err:
2322
    return ret;
2323
}
2324

2325
/* Set string - with known key length and known value length */
2326
int
2327
dict_set_nstrn(dict_t *this, char *key, const int keylen, char *str,
2328
               const int vallen)
2329
{
2330
    data_t *data = strn_to_data(str, vallen);
2331
    int ret = 0;
2332

2333
    if (!data) {
2334
        ret = -EINVAL;
2335
        goto err;
2336
    }
2337

2338
    ret = dict_setn(this, key, keylen, data);
2339
    if (ret < 0)
2340
        data_destroy(data);
2341

2342
err:
2343
    return ret;
2344
}
2345

2346
int
2347
dict_set_dynstr_with_alloc(dict_t *this, char *key, const char *str)
2348
{
2349
    char *alloc_str = gf_strdup(str);
2350
    int ret = -1;
2351

2352
    if (!alloc_str)
2353
        return ret;
2354

2355
    ret = dict_set_dynstr(this, key, alloc_str);
2356
    if (ret == -EINVAL)
2357
        GF_FREE(alloc_str);
2358

2359
    return ret;
2360
}
2361

2362
int
2363
dict_set_dynstr(dict_t *this, char *key, char *str)
2364
{
2365
    const int keylen = strlen(key);
2366
    return dict_set_dynstrn(this, key, keylen, str);
2367
}
2368

2369
int
2370
dict_set_dynstrn(dict_t *this, char *key, const int keylen, char *str)
2371
{
2372
    data_t *data = data_from_dynstr(str);
2373
    int ret = 0;
2374

2375
    if (!data) {
2376
        ret = -EINVAL;
2377
        goto err;
2378
    }
2379

2380
    ret = dict_setn(this, key, keylen, data);
2381
    if (ret < 0)
2382
        data_destroy(data);
2383

2384
err:
2385
    return ret;
2386
}
2387

2388
/* This function is called only by the volgen for now.
2389
   Check how else you can handle it */
2390
int
2391
dict_set_option(dict_t *this, char *key, char *str)
2392
{
2393
    data_t *data = data_from_dynstr(str);
2394
    int ret = 0;
2395

2396
    if (!data) {
2397
        ret = -EINVAL;
2398
        goto err;
2399
    }
2400

2401
    data->data_type = GF_DATA_TYPE_STR_OLD;
2402
    ret = dict_set(this, key, data);
2403
    if (ret < 0)
2404
        data_destroy(data);
2405
err:
2406
    return ret;
2407
}
2408

2409
int
2410
dict_add_dynstr_with_alloc(dict_t *this, char *key, char *str)
2411
{
2412
    data_t *data = NULL;
2413
    int ret = 0;
2414
    char *alloc_str = gf_strdup(str);
2415

2416
    if (!alloc_str)
2417
        goto out;
2418

2419
    data = data_from_dynstr(alloc_str);
2420
    if (!data) {
2421
        GF_FREE(alloc_str);
2422
        ret = -EINVAL;
2423
        goto out;
2424
    }
2425

2426
    ret = dict_add(this, key, data);
2427
    if (ret < 0)
2428
        data_destroy(data);
2429

2430
out:
2431
    return ret;
2432
}
2433

2434
int
2435
dict_get_bin(dict_t *this, char *key, void **bin)
2436
{
2437
    data_t *data = NULL;
2438
    int ret = -EINVAL;
2439

2440
    if (!bin) {
2441
        goto err;
2442
    }
2443

2444
    ret = dict_get_with_ref(this, key, &data);
2445
    if (ret < 0) {
2446
        goto err;
2447
    }
2448

2449
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_PTR, key, ret);
2450

2451
    *bin = data->data;
2452

2453
err:
2454
    if (data)
2455
        data_unref(data);
2456

2457
    return 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
 *******************************************************************/
2469
static int
2470
dict_setn_bin_common(dict_t *this, char *key, const int keylen, void *ptr,
2471
                     size_t size, gf_boolean_t is_static,
2472
                     gf_dict_data_type_t type)
2473
{
2474
    data_t *data = NULL;
2475
    int ret = 0;
2476

2477
    if (!ptr || (size > DICT_KEY_VALUE_MAX_SIZE)) {
2478
        ret = -EINVAL;
2479
        goto err;
2480
    }
2481

2482
    data = bin_to_data(ptr, size);
2483
    if (!data) {
2484
        ret = -EINVAL;
2485
        goto err;
2486
    }
2487

2488
    data->is_static = is_static;
2489
    data->data_type = type;
2490

2491
    ret = dict_setn(this, key, keylen, data);
2492
    if (ret < 0) {
2493
        /* don't free data->data, let callers handle it */
2494
        data->data = NULL;
2495
        data_destroy(data);
2496
    }
2497

2498
err:
2499
    return 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
 *******************************************************************/
2509
int
2510
dict_setn_bin(dict_t *this, char *key, const int keylen, void *ptr, size_t size)
2511
{
2512
    return dict_setn_bin_common(this, key, keylen, ptr, size, _gf_false,
2513
                                GF_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
 *******************************************************************/
2523
int
2524
dict_setn_static_bin(dict_t *this, char *key, const int keylen, void *ptr,
2525
                     size_t size)
2526
{
2527
    return dict_setn_bin_common(this, key, keylen, ptr, size, _gf_true,
2528
                                GF_DATA_TYPE_PTR);
2529
}
2530

2531
int
2532
dict_setn_gfuuid(dict_t *this, char *key, const int keylen, uuid_t gfid,
2533
                 bool is_static)
2534
{
2535
    return dict_setn_bin_common(this, key, keylen, gfid, sizeof(uuid_t),
2536
                                is_static, GF_DATA_TYPE_GFUUID);
2537
}
2538

2539
int
2540
dict_get_gfuuid(dict_t *this, char *key, uuid_t *gfid)
2541
{
2542
    data_t *data = NULL;
2543
    int ret = -EINVAL;
2544

2545
    if (!gfid) {
2546
        goto err;
2547
    }
2548
    ret = dict_get_with_ref(this, key, &data);
2549
    if (ret < 0) {
2550
        goto err;
2551
    }
2552

2553
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_GFUUID, key, -EINVAL);
2554

2555
    memcpy(*gfid, data->data, min(data->len, sizeof(uuid_t)));
2556

2557
err:
2558
    if (data)
2559
        data_unref(data);
2560

2561
    return ret;
2562
}
2563

2564
int
2565
dict_set_mdata(dict_t *this, char *key, struct mdata_iatt *mdata,
2566
               bool is_static)
2567
{
2568
    return dict_setn_bin_common(this, key, strlen(key), mdata,
2569
                                sizeof(struct mdata_iatt), is_static,
2570
                                GF_DATA_TYPE_MDATA);
2571
}
2572

2573
int
2574
dict_get_mdata(dict_t *this, char *key, struct mdata_iatt *mdata)
2575
{
2576
    data_t *data = NULL;
2577
    int ret = -EINVAL;
2578

2579
    if (!mdata) {
2580
        goto err;
2581
    }
2582
    ret = dict_get_with_ref(this, key, &data);
2583
    if (ret < 0) {
2584
        goto err;
2585
    }
2586

2587
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_MDATA, key, -EINVAL);
2588
    if (data->len < sizeof(struct mdata_iatt)) {
2589
        gf_smsg("glusterfs", GF_LOG_ERROR, ENOBUFS, LG_MSG_UNDERSIZED_BUF,
2590
                "key=%s", key, NULL);
2591
        ret = -ENOBUFS;
2592
        goto err;
2593
    }
2594

2595
    memcpy(mdata, data->data, min(data->len, sizeof(struct mdata_iatt)));
2596

2597
err:
2598
    if (data)
2599
        data_unref(data);
2600

2601
    return ret;
2602
}
2603

2604
int
2605
dict_set_iatt(dict_t *this, char *key, struct iatt *iatt, bool is_static)
2606
{
2607
    return dict_setn_bin_common(this, key, strlen(key), iatt,
2608
                                sizeof(struct iatt), is_static,
2609
                                GF_DATA_TYPE_IATT);
2610
}
2611

2612
int
2613
dict_get_iatt(dict_t *this, char *key, struct iatt *iatt)
2614
{
2615
    data_t *data = NULL;
2616
    int ret = -EINVAL;
2617

2618
    if (!iatt) {
2619
        goto err;
2620
    }
2621
    ret = dict_get_with_ref(this, key, &data);
2622
    if (ret < 0) {
2623
        goto err;
2624
    }
2625

2626
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_IATT, key, -EINVAL);
2627

2628
    memcpy(iatt, data->data, min(data->len, sizeof(struct iatt)));
2629

2630
err:
2631
    if (data)
2632
        data_unref(data);
2633

2634
    return 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

2660
int
2661
dict_get_str_boolean(dict_t *this, char *key, int default_val)
2662
{
2663
    data_t *data = NULL;
2664
    gf_boolean_t boo = _gf_false;
2665
    int ret = 0;
2666

2667
    ret = dict_get_with_ref(this, key, &data);
2668
    if (ret < 0) {
2669
        if (ret == -ENOENT)
2670
            ret = default_val;
2671
        else
2672
            ret = -1;
2673
        goto err;
2674
    }
2675

2676
    VALIDATE_DATA_AND_LOG(data, GF_DATA_TYPE_INT, key, -EINVAL);
2677

2678
    ret = gf_strn2boolean(data->data, data->len - 1, &boo);
2679
    if (ret == -1)
2680
        goto err;
2681

2682
    ret = boo;
2683

2684
err:
2685
    if (data)
2686
        data_unref(data);
2687

2688
    return ret;
2689
}
2690

2691
int
2692
dict_rename_key(dict_t *this, char *key, char *replace_key)
2693
{
2694
    data_pair_t *pair = NULL;
2695
    int ret = -EINVAL;
2696
    int replacekey_len = 0;
2697

2698
    /* replacing a key by itself is a NO-OP */
2699
    if (strcmp(key, replace_key) == 0)
2700
        return 0;
2701

2702
    if (!this) {
2703
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
2704
                         "dict is NULL");
2705
        return ret;
2706
    }
2707

2708
    replacekey_len = strlen(replace_key);
2709

2710
    LOCK(&this->lock);
2711
    {
2712
        /* no need to data_ref(pair->value), dict_set_lk() does it */
2713
        pair = dict_lookup_common(this, key);
2714
        if (!pair)
2715
            ret = -ENODATA;
2716
        else
2717
            ret = dict_set_lk(this, replace_key, replacekey_len, pair->value,
2718
                              1);
2719
    }
2720
    UNLOCK(&this->lock);
2721

2722
    if (!ret)
2723
        /* only delete the key on success */
2724
        dict_del(this, key);
2725

2726
    return 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

2746
unsigned int
2747
dict_serialized_length_lk(dict_t *this)
2748
{
2749
    unsigned int count = this->count;
2750
    const unsigned int keyhdrlen = DICT_DATA_HDR_KEY_LEN +
2751
                                   DICT_DATA_HDR_VAL_LEN;
2752

2753
    return 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

2768
static int
2769
dict_serialize_lk(dict_t *this, char *buf)
2770
{
2771
    int ret = -1;
2772
    data_pair_t *pair = this->members_list;
2773
    uint32_t count = this->count;
2774
    uint32_t keylen = 0;
2775
    uint32_t netword = 0;
2776

2777
    if (!buf) {
2778
        gf_smsg("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG, NULL);
2779
        goto out;
2780
    }
2781

2782
    netword = htobe32(count);
2783
    memcpy(buf, &netword, sizeof(netword));
2784
    buf += DICT_HDR_LEN;
2785

2786
    while (count) {
2787
        if (!pair) {
2788
            gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT,
2789
                    NULL);
2790
            goto out;
2791
        }
2792

2793
        keylen = strlen(pair->key);
2794
        netword = htobe32(keylen);
2795
        memcpy(buf, &netword, sizeof(netword));
2796
        buf += DICT_DATA_HDR_KEY_LEN;
2797

2798
        if (!pair->value) {
2799
            gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_PTR, NULL);
2800
            goto out;
2801
        }
2802

2803
        netword = htobe32(pair->value->len);
2804
        memcpy(buf, &netword, sizeof(netword));
2805
        buf += DICT_DATA_HDR_VAL_LEN;
2806

2807
        memcpy(buf, pair->key, keylen);
2808
        buf += keylen;
2809
        *buf++ = '\0';
2810

2811
        if (pair->value->data) {
2812
            memcpy(buf, pair->value->data, pair->value->len);
2813
            buf += pair->value->len;
2814
        }
2815

2816
        pair = pair->next;
2817
        count--;
2818
    }
2819

2820
    ret = 0;
2821
out:
2822
    return 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

2836
int32_t
2837
dict_unserialize(char *orig_buf, int32_t size, dict_t **fill)
2838
{
2839
    char *buf = orig_buf;
2840
    int ret = -1;
2841
    uint32_t count = 0;
2842
    int i = 0;
2843

2844
    data_t *value = NULL;
2845
    char *key = NULL;
2846
    int32_t keylen = 0;
2847
    int32_t vallen = 0;
2848
    int32_t hostord = 0;
2849

2850
    if (!buf) {
2851
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
2852
                         "buf is null!");
2853
        goto out;
2854
    }
2855

2856
    if (size == 0) {
2857
        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
2858
                         "size is 0!");
2859
        goto out;
2860
    }
2861

2862
    if (!fill) {
2863
        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
2864
                         "fill is null!");
2865
        goto out;
2866
    }
2867

2868
    if (!*fill) {
2869
        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
2870
                         "*fill is null!");
2871
        goto out;
2872
    }
2873

2874
    if ((buf + DICT_HDR_LEN) > (orig_buf + size)) {
2875
        gf_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));
2879
        goto out;
2880
    }
2881

2882
    memcpy(&hostord, buf, sizeof(hostord));
2883
    count = be32toh(hostord);
2884
    buf += DICT_HDR_LEN;
2885

2886
    /* count will be set by the dict_set's below */
2887
    (*fill)->count = 0;
2888

2889
    for (i = 0; i < count; i++) {
2890
        if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) {
2891
            gf_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));
2897
            goto out;
2898
        }
2899
        memcpy(&hostord, buf, sizeof(hostord));
2900
        keylen = be32toh(hostord);
2901
        buf += DICT_DATA_HDR_KEY_LEN;
2902

2903
        if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) {
2904
            gf_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));
2910
            goto out;
2911
        }
2912
        memcpy(&hostord, buf, sizeof(hostord));
2913
        vallen = be32toh(hostord);
2914
        buf += DICT_DATA_HDR_VAL_LEN;
2915

2916
        if ((keylen < 0) || (vallen < 0)) {
2917
            gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
2918
                             "undersized length passed "
2919
                             "key:%d val:%d",
2920
                             keylen, vallen);
2921
            goto out;
2922
        }
2923
        if ((buf + keylen) > (orig_buf + size)) {
2924
            gf_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));
2928
            goto out;
2929
        }
2930
        key = buf;
2931
        buf += keylen + 1; /* for '\0' */
2932

2933
        if ((buf + vallen) > (orig_buf + size)) {
2934
            gf_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));
2938
            goto out;
2939
        }
2940
        value = get_new_data();
2941

2942
        if (!value) {
2943
            ret = -1;
2944
            goto out;
2945
        }
2946
        value->len = vallen;
2947
        value->data = gf_memdup(buf, vallen);
2948
        value->data_type = GF_DATA_TYPE_STR_OLD;
2949
        value->is_static = _gf_false;
2950
        buf += vallen;
2951

2952
        ret = dict_addn(*fill, key, keylen, value);
2953
        if (ret < 0)
2954
            goto out;
2955
    }
2956

2957
    ret = 0;
2958
out:
2959
    return 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

2973
int32_t
2974
dict_allocate_and_serialize(dict_t *this, char **buf, u_int *length)
2975
{
2976
    int ret = -EINVAL;
2977
    ssize_t len = 0;
2978

2979
    if (!this || !buf) {
2980
        gf_msg_debug("dict", 0, "dict OR buf is NULL");
2981
        goto out;
2982
    }
2983

2984
    LOCK(&this->lock);
2985
    {
2986
        len = dict_serialized_length_lk(this);
2987

2988
        *buf = GF_MALLOC(len, gf_common_mt_char);
2989
        if (*buf == NULL) {
2990
            ret = -ENOMEM;
2991
            goto unlock;
2992
        }
2993

2994
        ret = dict_serialize_lk(this, *buf);
2995
        if (ret < 0) {
2996
            GF_FREE(*buf);
2997
            *buf = NULL;
2998
            goto unlock;
2999
        }
3000

3001
        if (length != NULL) {
3002
            *length = len;
3003
        }
3004
    }
3005
unlock:
3006
    UNLOCK(&this->lock);
3007
out:
3008
    return 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
 */
3023
static int
3024
dict_serialize_value_with_delim_lk(dict_t *this, char *buf, int32_t *serz_len,
3025
                                   char delimiter)
3026
{
3027
    int ret = -1;
3028
    uint32_t count = this->count;
3029
    int32_t vallen = 0;
3030
    int32_t total_len = 0;
3031
    data_pair_t *pair = this->members_list;
3032

3033
    while (count) {
3034
        if (!pair) {
3035
            gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_PAIRS_LESS_THAN_COUNT,
3036
                    NULL);
3037
            goto out;
3038
        }
3039

3040
        if (!pair->value) {
3041
            gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_KEY_OR_VALUE_NULL, NULL);
3042
            goto out;
3043
        }
3044

3045
        if (!pair->value->data) {
3046
            gf_smsg("dict", GF_LOG_ERROR, 0, LG_MSG_NULL_VALUE_IN_DICT, NULL);
3047
            goto out;
3048
        }
3049

3050
        vallen = pair->value->len - 1;  // length includes \0
3051
        memcpy(buf, pair->value->data, vallen);
3052
        buf += vallen;
3053
        *buf++ = delimiter;
3054

3055
        total_len += (vallen + 1);
3056

3057
        pair = pair->next;
3058
        count--;
3059
    }
3060

3061
    *--buf = '\0';  // remove the last delimiter
3062
    total_len--;    // adjust the length
3063
    ret = 0;
3064

3065
    if (serz_len)
3066
        *serz_len = total_len;
3067

3068
out:
3069
    return ret;
3070
}
3071

3072
int
3073
dict_serialize_value_with_delim(dict_t *this, char *buf, int32_t *serz_len,
3074
                                char delimiter)
3075
{
3076
    int ret = -1;
3077

3078
    if (!this || !buf) {
3079
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
3080
                         "dict is null!");
3081
        goto out;
3082
    }
3083

3084
    LOCK(&this->lock);
3085
    {
3086
        ret = dict_serialize_value_with_delim_lk(this, buf, serz_len,
3087
                                                 delimiter);
3088
    }
3089
    UNLOCK(&this->lock);
3090
out:
3091
    return ret;
3092
}
3093

3094
int
3095
dict_dump_to_str(dict_t *dict, char *dump, int dumpsize, char *format)
3096
{
3097
    int ret = 0;
3098
    int dumplen = 0;
3099
    data_pair_t *trav = NULL;
3100

3101
    if (!dict)
3102
        return 0;
3103

3104
    for (trav = dict->members_list; trav; trav = trav->next) {
3105
        ret = snprintf(&dump[dumplen], dumpsize - dumplen, format, trav->key,
3106
                       trav->value->data);
3107
        if ((ret == -1) || !ret)
3108
            return ret;
3109

3110
        dumplen += ret;
3111
    }
3112
    return 0;
3113
}
3114

3115
void
3116
dict_dump_to_log(dict_t *dict)
3117
{
3118
    int ret = -1;
3119
    char *dump = NULL;
3120
    const int dump_size = 64 * 1024;
3121
    char *format = "(%s:%s)";
3122

3123
    if (!dict) {
3124
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
3125
                         "dict is NULL");
3126
        goto out;
3127
    }
3128

3129
    dump = GF_MALLOC(dump_size, gf_common_mt_char);
3130
    if (!dump) {
3131
        gf_msg_callingfn("dict", GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY,
3132
                         "dump buffer is NULL");
3133
        goto out;
3134
    }
3135

3136
    ret = dict_dump_to_str(dict, dump, dump_size, format);
3137
    if (ret) {
3138
        gf_smsg("dict", GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, NULL);
3139
        goto out;
3140
    }
3141
    gf_smsg("dict", GF_LOG_INFO, 0, LG_MSG_DICT_ERROR, "dict=%p", dict,
3142
            "dump=%s", dump, NULL);
3143
out:
3144
    GF_FREE(dump);
3145

3146
    return;
3147
}
3148

3149
void
3150
dict_dump_to_statedump(dict_t *dict, char *dict_name, char *domain)
3151
{
3152
    int ret = -1;
3153
    char *dump = NULL;
3154
    const int dump_size = 64 * 1024;
3155
    char key[4096] = {
3156
        0,
3157
    };
3158
    char *format = "\n\t%s:%s";
3159

3160
    if (!dict) {
3161
        gf_msg_callingfn(domain, GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
3162
                         "dict is NULL");
3163
        goto out;
3164
    }
3165

3166
    dump = GF_MALLOC(dump_size, gf_common_mt_char);
3167
    if (!dump) {
3168
        gf_msg_callingfn(domain, GF_LOG_WARNING, ENOMEM, LG_MSG_NO_MEMORY,
3169
                         "dump buffer is NULL");
3170
        goto out;
3171
    }
3172

3173
    ret = dict_dump_to_str(dict, dump, dump_size, format);
3174
    if (ret) {
3175
        gf_smsg(domain, GF_LOG_WARNING, 0, LG_MSG_FAILED_TO_LOG_DICT, "name=%s",
3176
                dict_name, NULL);
3177
        goto out;
3178
    }
3179
    gf_proc_dump_build_key(key, domain, "%s", dict_name);
3180
    gf_proc_dump_write(key, "%s", dump);
3181

3182
out:
3183
    GF_FREE(dump);
3184

3185
    return;
3186
}
3187

3188
dict_t *
3189
dict_for_key_value(const char *name, const char *value, size_t size,
3190
                   gf_boolean_t is_static)
3191
{
3192
    dict_t *xattr = dict_new();
3193
    int ret = 0;
3194

3195
    if (!xattr)
3196
        return NULL;
3197

3198
    if (is_static)
3199
        ret = dict_set_static_bin(xattr, (char *)name, (void *)value, size);
3200
    else
3201
        ret = dict_set_bin(xattr, (char *)name, (void *)value, size);
3202

3203
    if (ret) {
3204
        dict_destroy(xattr);
3205
        xattr = NULL;
3206
    }
3207

3208
    return xattr;
3209
}
3210

3211
/*
3212
 * "strings" should be NULL terminated strings array.
3213
 */
3214
int
3215
dict_has_key_from_array(dict_t *dict, char **strings, gf_boolean_t *result)
3216
{
3217
    int i = 0;
3218

3219
    if (!dict || !strings || !result)
3220
        return -EINVAL;
3221

3222
    LOCK(&dict->lock);
3223
    {
3224
        for (i = 0; strings[i]; i++) {
3225
            if (dict_lookup_common(dict, strings[i])) {
3226
                *result = _gf_true;
3227
                goto unlock;
3228
            }
3229
        }
3230
        *result = _gf_false;
3231
    }
3232
unlock:
3233
    UNLOCK(&dict->lock);
3234
    return 0;
3235
}
3236

3237
/* Popluate specific dictionary on the basis of passed key array at the
3238
   time of unserialize buffer
3239
*/
3240
int32_t
3241
dict_unserialize_specific_keys(char *orig_buf, int32_t size, dict_t **fill,
3242
                               char **suffix_key_arr, dict_t **specific_dict,
3243
                               int totkeycount)
3244
{
3245
    char *buf = orig_buf;
3246
    int ret = -1;
3247
    uint32_t count = 0;
3248
    int i = 0;
3249
    int j = 0;
3250

3251
    data_t *value = NULL;
3252
    char *key = NULL;
3253
    int32_t keylen = 0;
3254
    int32_t vallen = 0;
3255
    int32_t hostord = 0;
3256
    int32_t keylenarr[totkeycount];
3257

3258
    if (!buf) {
3259
        gf_msg_callingfn("dict", GF_LOG_WARNING, EINVAL, LG_MSG_INVALID_ARG,
3260
                         "buf is null!");
3261
        goto out;
3262
    }
3263

3264
    if (size == 0) {
3265
        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
3266
                         "size is 0!");
3267
        goto out;
3268
    }
3269

3270
    if (!fill) {
3271
        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
3272
                         "fill is null!");
3273
        goto out;
3274
    }
3275

3276
    if (!*fill) {
3277
        gf_msg_callingfn("dict", GF_LOG_ERROR, EINVAL, LG_MSG_INVALID_ARG,
3278
                         "*fill is null!");
3279
        goto out;
3280
    }
3281

3282
    if ((buf + DICT_HDR_LEN) > (orig_buf + size)) {
3283
        gf_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));
3287
        goto out;
3288
    }
3289

3290
    memcpy(&hostord, buf, sizeof(hostord));
3291
    count = be32toh(hostord);
3292
    buf += DICT_HDR_LEN;
3293

3294
    /* Compute specific key length and save in array */
3295
    for (i = 0; i < totkeycount; i++) {
3296
        keylenarr[i] = strlen(suffix_key_arr[i]);
3297
    }
3298

3299
    for (i = 0; i < count; i++) {
3300
        if ((buf + DICT_DATA_HDR_KEY_LEN) > (orig_buf + size)) {
3301
            gf_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));
3307
            goto out;
3308
        }
3309
        memcpy(&hostord, buf, sizeof(hostord));
3310
        keylen = be32toh(hostord);
3311
        buf += DICT_DATA_HDR_KEY_LEN;
3312

3313
        if ((buf + DICT_DATA_HDR_VAL_LEN) > (orig_buf + size)) {
3314
            gf_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));
3320
            goto out;
3321
        }
3322
        memcpy(&hostord, buf, sizeof(hostord));
3323
        vallen = be32toh(hostord);
3324
        buf += DICT_DATA_HDR_VAL_LEN;
3325

3326
        if ((keylen < 0) || (vallen < 0)) {
3327
            gf_msg_callingfn("dict", GF_LOG_ERROR, 0, LG_MSG_UNDERSIZED_BUF,
3328
                             "undersized length passed "
3329
                             "key:%d val:%d",
3330
                             keylen, vallen);
3331
            goto out;
3332
        }
3333
        if ((buf + keylen) > (orig_buf + size)) {
3334
            gf_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));
3338
            goto out;
3339
        }
3340
        key = buf;
3341
        buf += keylen + 1; /* for '\0' */
3342

3343
        if ((buf + vallen) > (orig_buf + size)) {
3344
            gf_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));
3348
            goto out;
3349
        }
3350
        value = get_new_data();
3351

3352
        if (!value) {
3353
            ret = -1;
3354
            goto out;
3355
        }
3356
        value->len = vallen;
3357
        value->data = gf_memdup(buf, vallen);
3358
        value->data_type = GF_DATA_TYPE_STR_OLD;
3359
        value->is_static = _gf_false;
3360
        buf += vallen;
3361

3362
        ret = dict_addn(*fill, key, keylen, value);
3363
        if (ret < 0) {
3364
            data_destroy(value);
3365
            goto out;
3366
        }
3367
        for (j = 0; j < totkeycount; j++) {
3368
            if (keylen > keylenarr[j]) {
3369
                if (!strcmp(key + keylen - keylenarr[j], suffix_key_arr[j])) {
3370
                    ret = dict_addn(*specific_dict, key, keylen, value);
3371
                    break;
3372
                }
3373
            }
3374
        }
3375

3376
        if (ret < 0)
3377
            goto out;
3378
    }
3379

3380
    ret = 0;
3381
out:
3382
    return ret;
3383
}
3384

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.