~ubuntu-branches/ubuntu/oneiric/jabberd2/oneiric-security

« back to all changes in this revision

Viewing changes to sm/storage_db.c

  • Committer: Bazaar Package Importer
  • Author(s): Nicolai Spohrer
  • Date: 2008-08-12 16:13:43 UTC
  • mfrom: (1.1.3 upstream) (0.1.2 sid)
  • Revision ID: james.westby@ubuntu.com-20080812161343-6trz3r97dtevxd17
Tags: 2.2.1-1ubuntu1
* Merge with Debian unstable (LP: #257130), remaining changes:
  - debian/control:
    + Modify Maintainer field as per spec
    + Depend on libdb4.6-dev instead of libdb4.4-dev
    + Added Conflicts and Replaces: ..., jabber for jabberd2
  - debian/rules: Added libtoolize call (jabberd2 ships with
     an older ltmain.sh version that conflicts with the
     current libtool version)
  - debian/init: create /var/run/jabber directory with correct
     permissions
* Dropped changes:
  - Debian already depends on libpq-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * jabberd - Jabber Open Source Server
3
 
 * Copyright (c) 2002 Jeremie Miller, Thomas Muldowney,
4
 
 *                    Ryan Eatmon, Robert Norris
5
 
 *
6
 
 * This program is free software; you can redistribute it and/or modify
7
 
 * it under the terms of the GNU General Public License as published by
8
 
 * the Free Software Foundation; either version 2 of the License, or
9
 
 * (at your option) any later version.
10
 
 *
11
 
 * This program is distributed in the hope that it will be useful,
12
 
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
14
 
 * GNU General Public License for more details.
15
 
 *
16
 
 * You should have received a copy of the GNU General Public License
17
 
 * along with this program; if not, write to the Free Software
18
 
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
19
 
 */
20
 
 
21
 
/** @file sm/storage_db.c
22
 
  * @brief berkeley db storage module
23
 
  * @author Robert Norris
24
 
  * $Date: 2005/03/23 19:59:01 $
25
 
  * $Revision: 1.19.2.10 $
26
 
  */
27
 
 
28
 
/*
29
 
 * !!! we must catch DB_RUNRECOVERY and call _st_db_panic(). I would argue that
30
 
 *     Berkeley should do this for all cases, not just for the process that
31
 
 *     caused the fault, but I'm not sure they see it that way. (I have asked,
32
 
 *     just waiting for a reply)
33
 
 *
34
 
 *     Sleepycat SR#7019 resolved this. There is an unreleased patch available
35
 
 *     (I have a copy) that will be in 4.2 (due in June).
36
 
 */
37
 
 
38
 
#include "sm.h"
39
 
 
40
 
#ifdef STORAGE_DB
41
 
 
42
 
#include <db.h>
43
 
 
44
 
/** internal structure, holds our data */
45
 
typedef struct drvdata_st {
46
 
    DB_ENV *env;
47
 
 
48
 
    char *path;
49
 
    int sync;
50
 
 
51
 
    xht dbs;
52
 
 
53
 
    xht filters;
54
 
} *drvdata_t;
55
 
 
56
 
/** internal structure, holds a single db handle */
57
 
typedef struct dbdata_st {
58
 
    drvdata_t data;
59
 
 
60
 
    DB *db;
61
 
} *dbdata_t;
62
 
 
63
 
/* union for strict alias rules in gcc3 */
64
 
union xhashv {
65
 
  void **val;
66
 
  dbdata_t *dbd_val;
67
 
};
68
 
 
69
 
static st_ret_t _st_db_add_type(st_driver_t drv, const char *type) {
70
 
    drvdata_t data = (drvdata_t) drv->private;
71
 
    dbdata_t dbd;
72
 
    int err;
73
 
    
74
 
    dbd = (dbdata_t) malloc(sizeof(struct dbdata_st));
75
 
    memset(dbd, 0, sizeof(struct dbdata_st));
76
 
 
77
 
    dbd->data = data;
78
 
 
79
 
    if((err = db_create(&(dbd->db), data->env, 0)) != 0) {
80
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't create db handle: %s", db_strerror(err));
81
 
        free(dbd);
82
 
        return st_FAILED;
83
 
    }
84
 
 
85
 
    if((err = dbd->db->set_flags(dbd->db, DB_DUP)) != 0) {
86
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't set database for duplicate storage: %s", db_strerror(err));
87
 
        dbd->db->close(dbd->db, 0);
88
 
        free(dbd);
89
 
        return st_FAILED;
90
 
    }
91
 
 
92
 
    if((err = dbd->db->open(dbd->db, NULL, "sm.db", type, DB_HASH, DB_AUTO_COMMIT | DB_CREATE, 0)) != 0) {
93
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't open storage db: %s", db_strerror(err));
94
 
        dbd->db->close(dbd->db, 0);
95
 
        free(dbd);
96
 
        return st_FAILED;
97
 
    }
98
 
 
99
 
    xhash_put(data->dbs, type, dbd);
100
 
 
101
 
    return st_SUCCESS;
102
 
}
103
 
 
104
 
/** make a new cursor (optionally wrapped in a txn) */
105
 
static st_ret_t _st_db_cursor_new(st_driver_t drv, dbdata_t dbd, DBC **cursor, DB_TXN **txnid) {
106
 
    int err;
107
 
 
108
 
    if(txnid != NULL)
109
 
        if((err = dbd->data->env->txn_begin(dbd->data->env, NULL, txnid, DB_TXN_SYNC)) != 0) {
110
 
            log_write(drv->st->sm->log, LOG_ERR, "db: couldn't begin new transaction: %s", db_strerror(err));
111
 
            return st_FAILED;
112
 
        }
113
 
 
114
 
    if(txnid == NULL)
115
 
        err = dbd->db->cursor(dbd->db, NULL, cursor, 0);
116
 
    else
117
 
        err = dbd->db->cursor(dbd->db, *txnid, cursor, 0);
118
 
 
119
 
    if(err != 0) {
120
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't create cursor: %s", db_strerror(err));
121
 
        if(txnid != NULL)
122
 
            (*txnid)->abort(*txnid);
123
 
        return st_FAILED;
124
 
    }
125
 
 
126
 
    return st_SUCCESS;
127
 
}
128
 
 
129
 
/** close down a cursor */
130
 
static st_ret_t _st_db_cursor_free(st_driver_t drv, dbdata_t dbd, DBC *cursor, DB_TXN *txnid) {
131
 
    int err;
132
 
 
133
 
    if((err = cursor->c_close(cursor)) != 0) {
134
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't close cursor: %s", db_strerror(err));
135
 
        if(txnid != NULL)
136
 
            txnid->abort(txnid);
137
 
        return st_FAILED;
138
 
    }
139
 
 
140
 
    if(txnid != NULL)
141
 
        if((err = txnid->commit(txnid, DB_TXN_SYNC)) != 0) {
142
 
            log_write(drv->st->sm->log, LOG_ERR, "db: couldn't commit transaction: %s", db_strerror(err));
143
 
            return st_FAILED;
144
 
        }
145
 
 
146
 
    return st_SUCCESS;
147
 
}
148
 
 
149
 
static void _st_db_object_serialise(os_object_t o, char **buf, int *len) {
150
 
    char *key, *xml, *xmlstr;
151
 
    void *val;
152
 
    os_type_t ot;
153
 
    int cur = 0, xlen;
154
 
 
155
 
    log_debug(ZONE, "serialising object");
156
 
 
157
 
    *buf = NULL;
158
 
    *len = 0;
159
 
 
160
 
    if(os_object_iter_first(o))
161
 
        do {
162
 
            os_object_iter_get(o, &key, &val, &ot);
163
 
            
164
 
            log_debug(ZONE, "serialising key %s", key);
165
 
 
166
 
            ser_string_set(key, &cur, buf, len);
167
 
            ser_int_set(ot, &cur, buf, len);
168
 
 
169
 
            switch(ot) {
170
 
                case os_type_BOOLEAN:
171
 
                    ser_int_set(((int) val) != 0, &cur, buf, len);
172
 
                    break;
173
 
 
174
 
                case os_type_INTEGER:
175
 
                    ser_int_set((int) val, &cur, buf, len);
176
 
                    break;
177
 
 
178
 
                case os_type_STRING:
179
 
                    ser_string_set((char *) val, &cur, buf, len);
180
 
                    break;
181
 
 
182
 
                case os_type_NAD:
183
 
                    nad_print((nad_t) val, 0, &xml, &xlen);
184
 
                    xmlstr = (char *) malloc(sizeof(char) * (xlen + 1));
185
 
                    sprintf(xmlstr, "%.*s", xlen, xml);
186
 
                    ser_string_set(xmlstr, &cur, buf, len);
187
 
                    free(xmlstr);
188
 
                    break;
189
 
 
190
 
                case os_type_UNKNOWN:
191
 
                    break;
192
 
            }
193
 
        } while(os_object_iter_next(o));
194
 
 
195
 
    *len = cur;
196
 
}
197
 
 
198
 
static os_object_t _st_db_object_deserialise(st_driver_t drv, os_t os, const char *buf, int len) {
199
 
    os_object_t o;
200
 
    int cur;
201
 
    char *key, *sval;
202
 
    int ot;
203
 
    int ival;
204
 
    nad_t nad;
205
 
 
206
 
    log_debug(ZONE, "deserialising object");
207
 
 
208
 
    o = os_object_new(os);
209
 
 
210
 
    cur = 0;
211
 
    while(cur < len) {
212
 
        if(ser_string_get(&key, &cur, buf, len) != 0 || ser_int_get(&ot, &cur, buf, len) != 0) {
213
 
            log_debug(ZONE, "ran off the end of the buffer");
214
 
            return o;
215
 
        }
216
 
 
217
 
        log_debug(ZONE, "deserialising key %s", key);
218
 
 
219
 
        switch((os_type_t) ot) {
220
 
            case os_type_BOOLEAN:
221
 
                ser_int_get(&ival, &cur, buf, len);
222
 
                ival = (ival != 0);
223
 
                os_object_put(o, key, &ival, os_type_BOOLEAN);
224
 
                break;
225
 
 
226
 
            case os_type_INTEGER:
227
 
                ser_int_get(&ival, &cur, buf, len);
228
 
                os_object_put(o, key, &ival, os_type_INTEGER);
229
 
                break;
230
 
 
231
 
            case os_type_STRING:
232
 
                ser_string_get(&sval, &cur, buf, len);
233
 
                os_object_put(o, key, sval, os_type_STRING);
234
 
                free(sval);
235
 
                break;
236
 
 
237
 
            case os_type_NAD:
238
 
                ser_string_get(&sval, &cur, buf, len);
239
 
                nad = nad_parse(drv->st->sm->router->nad_cache, sval, strlen(sval));
240
 
                free(sval);
241
 
                if(nad == NULL) {
242
 
                    log_write(drv->st->sm->log, LOG_ERR, "db: unable to parse stored XML - database corruption?");
243
 
                    return NULL;
244
 
                }
245
 
                os_object_put(o, key, nad, os_type_NAD);
246
 
                nad_free(nad);
247
 
                break;
248
 
  
249
 
           case os_type_UNKNOWN:
250
 
                break;
251
 
        }
252
 
 
253
 
        free(key);
254
 
    }
255
 
 
256
 
    return o;
257
 
}
258
 
 
259
 
static st_ret_t _st_db_put_guts(st_driver_t drv, const char *type, const char *owner, os_t os, dbdata_t dbd, DBC *c, DB_TXN *t) {
260
 
    DBT key, val;
261
 
    os_object_t o;
262
 
    char *buf;
263
 
    int len, err;
264
 
 
265
 
    memset(&key, 0, sizeof(DBT));
266
 
    memset(&val, 0, sizeof(DBT));
267
 
 
268
 
    key.data = (char *) owner;
269
 
    key.size = strlen(owner);
270
 
 
271
 
    if(os_iter_first(os))
272
 
        do {
273
 
            o = os_iter_object(os);
274
 
            _st_db_object_serialise(o, &buf, &len);
275
 
 
276
 
            val.data = buf;
277
 
            val.size = len;
278
 
        
279
 
            if((err = c->c_put(c, &key, &val, DB_KEYLAST)) != 0) {
280
 
                log_write(drv->st->sm->log, LOG_ERR, "db: couldn't store value for type %s owner %s in storage db: %s", type, owner, db_strerror(err));
281
 
                free(buf);
282
 
                return st_FAILED;
283
 
            }
284
 
 
285
 
            free(buf);
286
 
 
287
 
        } while(os_iter_next(os));
288
 
 
289
 
    return st_SUCCESS;
290
 
}
291
 
 
292
 
static st_ret_t _st_db_put(st_driver_t drv, const char *type, const char *owner, os_t os) {
293
 
    drvdata_t data = (drvdata_t) drv->private;
294
 
    dbdata_t dbd = xhash_get(data->dbs, type);
295
 
    DBC *c;
296
 
    DB_TXN *t;
297
 
    st_ret_t ret;
298
 
 
299
 
    if(os_count(os) == 0)
300
 
        return st_SUCCESS;
301
 
 
302
 
    ret = _st_db_cursor_new(drv, dbd, &c, &t);
303
 
    if(ret != st_SUCCESS)
304
 
        return ret;
305
 
 
306
 
    ret = _st_db_put_guts(drv, type, owner, os, dbd, c, t);
307
 
    if(ret != st_SUCCESS) {
308
 
        t->abort(t);
309
 
        _st_db_cursor_free(drv, dbd, c, NULL);
310
 
        return st_FAILED;
311
 
    }
312
 
 
313
 
    return _st_db_cursor_free(drv, dbd, c, t);
314
 
}
315
 
 
316
 
static st_ret_t _st_db_get(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t *os) {
317
 
    drvdata_t data = (drvdata_t) drv->private;
318
 
    dbdata_t dbd = xhash_get(data->dbs, type);
319
 
    DBC *c;
320
 
    DB_TXN *t;
321
 
    st_ret_t ret;
322
 
    DBT key, val;
323
 
    st_filter_t f;
324
 
    int err;
325
 
    os_object_t o;
326
 
    char *cfilter;
327
 
 
328
 
    ret = _st_db_cursor_new(drv, dbd, &c, &t);
329
 
    if(ret != st_SUCCESS)
330
 
        return ret;
331
 
 
332
 
    f = NULL;
333
 
    if(filter != NULL) {
334
 
        f = xhash_get(data->filters, filter);
335
 
        if(f == NULL) {
336
 
            f = storage_filter(filter);
337
 
            cfilter = pstrdup(xhash_pool(data->filters), filter);
338
 
            xhash_put(data->filters, cfilter, (void *) f);
339
 
            pool_cleanup(xhash_pool(data->filters), (pool_cleaner) pool_free, f->p);
340
 
        }
341
 
    }
342
 
 
343
 
    memset(&key, 0, sizeof(DBT));
344
 
    memset(&val, 0, sizeof(DBT));
345
 
 
346
 
    key.data = (char *) owner;
347
 
    key.size = strlen(owner);
348
 
 
349
 
    *os = os_new();
350
 
 
351
 
    err = c->c_get(c, &key, &val, DB_SET);
352
 
    while(err == 0) {
353
 
        o = _st_db_object_deserialise(drv, *os, val.data, val.size);
354
 
 
355
 
        if(o != NULL && !storage_match(f, o, *os))
356
 
            os_object_free(o);
357
 
 
358
 
        err = c->c_get(c, &key, &val, DB_NEXT_DUP);
359
 
    }
360
 
 
361
 
    if(err != 0 && err != DB_NOTFOUND) {
362
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't move cursor for type %s owner %s in storage db: %s", type, owner, db_strerror(err));
363
 
        t->abort(t);
364
 
        _st_db_cursor_free(drv, dbd, c, NULL);
365
 
        os_free(*os);
366
 
        return st_FAILED;
367
 
    }
368
 
 
369
 
    ret = _st_db_cursor_free(drv, dbd, c, t);
370
 
    if(ret != st_SUCCESS) {
371
 
        os_free(*os);
372
 
        return ret;
373
 
    }
374
 
 
375
 
    if(os_count(*os) == 0) {
376
 
        os_free(*os);
377
 
        return st_NOTFOUND;
378
 
    }
379
 
 
380
 
    return st_SUCCESS;
381
 
}
382
 
 
383
 
static st_ret_t _st_db_delete_guts(st_driver_t drv, const char *type, const char *owner, const char *filter, dbdata_t dbd, DBC *c, DB_TXN *t) {
384
 
    drvdata_t data = (drvdata_t) drv->private;
385
 
    DBT key, val;
386
 
    st_filter_t f;
387
 
    int err;
388
 
    os_t os;
389
 
    os_object_t o;
390
 
    char *cfilter;
391
 
 
392
 
    f = NULL;
393
 
    if(filter != NULL) {
394
 
        f = xhash_get(data->filters, filter);
395
 
        if(f == NULL) {
396
 
            f = storage_filter(filter);
397
 
            cfilter = pstrdup(xhash_pool(data->filters), filter);
398
 
            xhash_put(data->filters, cfilter, (void *) f);
399
 
            pool_cleanup(xhash_pool(data->filters), (pool_cleaner) pool_free, f->p);
400
 
        }
401
 
    }
402
 
 
403
 
    memset(&key, 0, sizeof(DBT));
404
 
    memset(&val, 0, sizeof(DBT));
405
 
 
406
 
    key.data = (char *) owner;
407
 
    key.size = strlen(owner);
408
 
 
409
 
    os = os_new();
410
 
 
411
 
    err = c->c_get(c, &key, &val, DB_SET);
412
 
    while(err == 0) {
413
 
        o = _st_db_object_deserialise(drv, os, val.data, val.size);
414
 
 
415
 
        if(o != NULL && storage_match(f, o, os))
416
 
            err = c->c_del(c, 0);
417
 
 
418
 
        if(err == 0)
419
 
            err = c->c_get(c, &key, &val, DB_NEXT_DUP);
420
 
    }
421
 
 
422
 
    os_free(os);
423
 
 
424
 
    if(err != 0 && err != DB_NOTFOUND) {
425
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't move cursor for type %s owner %s in storage db: %s", type, owner, db_strerror(err));
426
 
        return st_FAILED;
427
 
    }
428
 
 
429
 
    return st_SUCCESS;
430
 
}
431
 
 
432
 
static st_ret_t _st_db_delete(st_driver_t drv, const char *type, const char *owner, const char *filter) {
433
 
    drvdata_t data = (drvdata_t) drv->private;
434
 
    dbdata_t dbd = xhash_get(data->dbs, type);
435
 
    DBC *c;
436
 
    DB_TXN *t;
437
 
    st_ret_t ret;
438
 
 
439
 
    ret = _st_db_cursor_new(drv, dbd, &c, &t);
440
 
    if(ret != st_SUCCESS)
441
 
        return ret;
442
 
 
443
 
    ret = _st_db_delete_guts(drv, type, owner, filter, dbd, c, t);
444
 
    if(ret != st_SUCCESS) {
445
 
        t->abort(t);
446
 
        _st_db_cursor_free(drv, dbd, c, NULL);
447
 
        return st_FAILED;
448
 
    }
449
 
 
450
 
    return _st_db_cursor_free(drv, dbd, c, t);
451
 
}
452
 
 
453
 
static st_ret_t _st_db_replace(st_driver_t drv, const char *type, const char *owner, const char *filter, os_t os) {
454
 
    drvdata_t data = (drvdata_t) drv->private;
455
 
    dbdata_t dbd = xhash_get(data->dbs, type);
456
 
    DBC *c;
457
 
    DB_TXN *t;
458
 
    st_ret_t ret;
459
 
 
460
 
    ret = _st_db_cursor_new(drv, dbd, &c, &t);
461
 
    if(ret != st_SUCCESS)
462
 
        return ret;
463
 
 
464
 
    ret = _st_db_delete_guts(drv, type, owner, filter, dbd, c, t);
465
 
    if(ret != st_SUCCESS) {
466
 
        t->abort(t);
467
 
        _st_db_cursor_free(drv, dbd, c, NULL);
468
 
        return st_FAILED;
469
 
    }
470
 
 
471
 
    if(os_count(os) == 0)
472
 
        return _st_db_cursor_free(drv, dbd, c, t);
473
 
 
474
 
    ret = _st_db_put_guts(drv, type, owner, os, dbd, c, t);
475
 
    if(ret != st_SUCCESS) {
476
 
        t->abort(t);
477
 
        _st_db_cursor_free(drv, dbd, c, NULL);
478
 
        return st_FAILED;
479
 
    }
480
 
 
481
 
    return _st_db_cursor_free(drv, dbd, c, t);
482
 
}
483
 
 
484
 
static void _st_db_free(st_driver_t drv) {
485
 
    drvdata_t data = (drvdata_t) drv->private;
486
 
    const char *key;
487
 
    dbdata_t dbd;
488
 
    DB_ENV *env;
489
 
    union xhashv xhv;
490
 
 
491
 
    xhv.dbd_val = &dbd;
492
 
    if(xhash_iter_first(data->dbs))
493
 
        do {
494
 
            xhash_iter_get(data->dbs, &key, xhv.val);
495
 
 
496
 
            log_debug(ZONE, "closing %s db", key);
497
 
 
498
 
            dbd->db->close(dbd->db, 0);
499
 
            free(dbd);
500
 
        } while(xhash_iter_next(data->dbs));
501
 
 
502
 
    xhash_free(data->dbs);
503
 
 
504
 
    xhash_free(data->filters);
505
 
 
506
 
    data->env->close(data->env, 0);
507
 
 
508
 
    /* remove db environment files if no longer in use */
509
 
    if (db_env_create(&env, 0) == 0)
510
 
        env->remove(env, data->path, 0);
511
 
 
512
 
    free(data);
513
 
}
514
 
 
515
 
/** panic function */
516
 
static void _st_db_panic(DB_ENV *env, int errval) {
517
 
    log_t log = (log_t) env->app_private;
518
 
 
519
 
    log_write(log, LOG_CRIT, "db: corruption detected! close all jabberd processes and run db_recover");
520
 
 
521
 
    exit(2);
522
 
}
523
 
 
524
 
st_ret_t st_db_init(st_driver_t drv) {
525
 
    char *path;
526
 
    int err;
527
 
    DB_ENV *env;
528
 
    drvdata_t data;
529
 
 
530
 
    path = config_get_one(drv->st->sm->config, "storage.db.path", 0);
531
 
    if(path == NULL) {
532
 
        log_write(drv->st->sm->log, LOG_ERR, "db: no path specified in config file");
533
 
        return st_FAILED;
534
 
    }
535
 
 
536
 
    if((err = db_env_create(&env, 0)) != 0) {
537
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't create environment: %s", db_strerror(err));
538
 
        return st_FAILED;
539
 
    }
540
 
 
541
 
    if((err = env->set_paniccall(env, _st_db_panic)) != 0) {
542
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't set panic call: %s", db_strerror(err));
543
 
        return st_FAILED;
544
 
    }
545
 
 
546
 
    /* store the log context in case we panic */
547
 
    env->app_private = drv->st->sm->log;
548
 
 
549
 
    if((err = env->open(env, path, DB_INIT_LOCK | DB_INIT_MPOOL | DB_INIT_LOG | DB_INIT_TXN | DB_CREATE, 0)) != 0) {
550
 
        log_write(drv->st->sm->log, LOG_ERR, "db: couldn't open environment: %s", db_strerror(err));
551
 
        env->close(env, 0);
552
 
        return st_FAILED;
553
 
    }
554
 
 
555
 
    data = (drvdata_t) malloc(sizeof(struct drvdata_st));
556
 
    memset(data, 0, sizeof(struct drvdata_st));
557
 
 
558
 
    data->env = env;
559
 
    data->path = path;
560
 
 
561
 
    if(config_get_one(drv->st->sm->config, "storage.db.sync", 0) != NULL)
562
 
        data->sync = 1;
563
 
 
564
 
    data->dbs = xhash_new(101);
565
 
 
566
 
    data->filters = xhash_new(17);
567
 
 
568
 
    drv->private = (void *) data;
569
 
 
570
 
    drv->add_type = _st_db_add_type;
571
 
    drv->put = _st_db_put;
572
 
    drv->get = _st_db_get;
573
 
    drv->replace = _st_db_replace;
574
 
    drv->delete = _st_db_delete;
575
 
    drv->free = _st_db_free;
576
 
 
577
 
    return st_SUCCESS;
578
 
}
579
 
 
580
 
#endif