]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - contrib/bind9/lib/dns/sdb.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / contrib / bind9 / lib / dns / sdb.c
1 /*
2  * Copyright (C) 2004-2008  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 2000, 2001, 2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: sdb.c,v 1.45.18.16 2008/01/17 23:45:58 tbox Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <isc/buffer.h>
27 #include <isc/lex.h>
28 #include <isc/log.h>
29 #include <isc/magic.h>
30 #include <isc/mem.h>
31 #include <isc/once.h>
32 #include <isc/print.h>
33 #include <isc/region.h>
34 #include <isc/util.h>
35
36 #include <dns/callbacks.h>
37 #include <dns/db.h>
38 #include <dns/dbiterator.h>
39 #include <dns/fixedname.h>
40 #include <dns/log.h>
41 #include <dns/rdata.h>
42 #include <dns/rdatalist.h>
43 #include <dns/rdataset.h>
44 #include <dns/rdatasetiter.h>
45 #include <dns/rdatatype.h>
46 #include <dns/result.h>
47 #include <dns/sdb.h>
48 #include <dns/types.h>
49
50 #include "rdatalist_p.h"
51
52 struct dns_sdbimplementation {
53         const dns_sdbmethods_t          *methods;
54         void                            *driverdata;
55         unsigned int                    flags;
56         isc_mem_t                       *mctx;
57         isc_mutex_t                     driverlock;
58         dns_dbimplementation_t          *dbimp;
59 };
60
61 struct dns_sdb {
62         /* Unlocked */
63         dns_db_t                        common;
64         char                            *zone;
65         dns_sdbimplementation_t         *implementation;
66         void                            *dbdata;
67         isc_mutex_t                     lock;
68         /* Locked */
69         unsigned int                    references;
70 };
71
72 struct dns_sdblookup {
73         /* Unlocked */
74         unsigned int                    magic;
75         dns_sdb_t                       *sdb;
76         ISC_LIST(dns_rdatalist_t)       lists;
77         ISC_LIST(isc_buffer_t)          buffers;
78         dns_name_t                      *name;
79         ISC_LINK(dns_sdblookup_t)       link;
80         isc_mutex_t                     lock;
81         dns_rdatacallbacks_t            callbacks;
82         /* Locked */
83         unsigned int                    references;
84 };
85
86 typedef struct dns_sdblookup dns_sdbnode_t;
87
88 struct dns_sdballnodes {
89         dns_dbiterator_t                common;
90         ISC_LIST(dns_sdbnode_t)         nodelist;
91         dns_sdbnode_t                   *current;
92         dns_sdbnode_t                   *origin;
93 };
94
95 typedef dns_sdballnodes_t sdb_dbiterator_t;
96
97 typedef struct sdb_rdatasetiter {
98         dns_rdatasetiter_t              common;
99         dns_rdatalist_t                 *current;
100 } sdb_rdatasetiter_t;
101
102 #define SDB_MAGIC               ISC_MAGIC('S', 'D', 'B', '-')
103
104 /*%
105  * Note that "impmagic" is not the first four bytes of the struct, so
106  * ISC_MAGIC_VALID cannot be used.
107  */
108 #define VALID_SDB(sdb)          ((sdb) != NULL && \
109                                  (sdb)->common.impmagic == SDB_MAGIC)
110
111 #define SDBLOOKUP_MAGIC         ISC_MAGIC('S','D','B','L')
112 #define VALID_SDBLOOKUP(sdbl)   ISC_MAGIC_VALID(sdbl, SDBLOOKUP_MAGIC)
113 #define VALID_SDBNODE(sdbn)     VALID_SDBLOOKUP(sdbn)
114
115 /* These values are taken from RFC1537 */
116 #define SDB_DEFAULT_REFRESH     (60 * 60 * 8)
117 #define SDB_DEFAULT_RETRY       (60 * 60 * 2)
118 #define SDB_DEFAULT_EXPIRE      (60 * 60 * 24 * 7)
119 #define SDB_DEFAULT_MINIMUM     (60 * 60 * 24)
120
121 /* This is a reasonable value */
122 #define SDB_DEFAULT_TTL         (60 * 60 * 24)
123
124 #ifdef __COVERITY__
125 #define MAYBE_LOCK(sdb) LOCK(&sdb->implementation->driverlock)
126 #define MAYBE_UNLOCK(sdb) UNLOCK(&sdb->implementation->driverlock)
127 #else
128 #define MAYBE_LOCK(sdb)                                                 \
129         do {                                                            \
130                 unsigned int flags = sdb->implementation->flags;        \
131                 if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)              \
132                         LOCK(&sdb->implementation->driverlock);         \
133         } while (0)
134
135 #define MAYBE_UNLOCK(sdb)                                               \
136         do {                                                            \
137                 unsigned int flags = sdb->implementation->flags;        \
138                 if ((flags & DNS_SDBFLAG_THREADSAFE) == 0)              \
139                         UNLOCK(&sdb->implementation->driverlock);       \
140         } while (0)
141 #endif
142
143 static int dummy;
144
145 static isc_result_t dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin,
146                                    dns_dbtype_t type, dns_rdataclass_t rdclass,
147                                    unsigned int argc, char *argv[],
148                                    void *driverarg, dns_db_t **dbp);
149
150 static isc_result_t findrdataset(dns_db_t *db, dns_dbnode_t *node,
151                                  dns_dbversion_t *version,
152                                  dns_rdatatype_t type, dns_rdatatype_t covers,
153                                  isc_stdtime_t now, dns_rdataset_t *rdataset,
154                                  dns_rdataset_t *sigrdataset);
155
156 static isc_result_t createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep);
157
158 static void destroynode(dns_sdbnode_t *node);
159
160 static void detachnode(dns_db_t *db, dns_dbnode_t **targetp);
161
162
163 static void list_tordataset(dns_rdatalist_t *rdatalist,
164                             dns_db_t *db, dns_dbnode_t *node,
165                             dns_rdataset_t *rdataset);
166
167 static void             dbiterator_destroy(dns_dbiterator_t **iteratorp);
168 static isc_result_t     dbiterator_first(dns_dbiterator_t *iterator);
169 static isc_result_t     dbiterator_last(dns_dbiterator_t *iterator);
170 static isc_result_t     dbiterator_seek(dns_dbiterator_t *iterator,
171                                         dns_name_t *name);
172 static isc_result_t     dbiterator_prev(dns_dbiterator_t *iterator);
173 static isc_result_t     dbiterator_next(dns_dbiterator_t *iterator);
174 static isc_result_t     dbiterator_current(dns_dbiterator_t *iterator,
175                                            dns_dbnode_t **nodep,
176                                            dns_name_t *name);
177 static isc_result_t     dbiterator_pause(dns_dbiterator_t *iterator);
178 static isc_result_t     dbiterator_origin(dns_dbiterator_t *iterator,
179                                           dns_name_t *name);
180
181 static dns_dbiteratormethods_t dbiterator_methods = {
182         dbiterator_destroy,
183         dbiterator_first,
184         dbiterator_last,
185         dbiterator_seek,
186         dbiterator_prev,
187         dbiterator_next,
188         dbiterator_current,
189         dbiterator_pause,
190         dbiterator_origin
191 };
192
193 static void             rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp);
194 static isc_result_t     rdatasetiter_first(dns_rdatasetiter_t *iterator);
195 static isc_result_t     rdatasetiter_next(dns_rdatasetiter_t *iterator);
196 static void             rdatasetiter_current(dns_rdatasetiter_t *iterator,
197                                              dns_rdataset_t *rdataset);
198
199 static dns_rdatasetitermethods_t rdatasetiter_methods = {
200         rdatasetiter_destroy,
201         rdatasetiter_first,
202         rdatasetiter_next,
203         rdatasetiter_current
204 };
205
206 /*
207  * Functions used by implementors of simple databases
208  */
209 isc_result_t
210 dns_sdb_register(const char *drivername, const dns_sdbmethods_t *methods,
211                  void *driverdata, unsigned int flags, isc_mem_t *mctx,
212                  dns_sdbimplementation_t **sdbimp)
213 {
214         dns_sdbimplementation_t *imp;
215         isc_result_t result;
216
217         REQUIRE(drivername != NULL);
218         REQUIRE(methods != NULL);
219         REQUIRE(methods->lookup != NULL);
220         REQUIRE(mctx != NULL);
221         REQUIRE(sdbimp != NULL && *sdbimp == NULL);
222         REQUIRE((flags & ~(DNS_SDBFLAG_RELATIVEOWNER |
223                            DNS_SDBFLAG_RELATIVERDATA |
224                            DNS_SDBFLAG_THREADSAFE)) == 0);
225
226         imp = isc_mem_get(mctx, sizeof(dns_sdbimplementation_t));
227         if (imp == NULL)
228                 return (ISC_R_NOMEMORY);
229         imp->methods = methods;
230         imp->driverdata = driverdata;
231         imp->flags = flags;
232         imp->mctx = NULL;
233         isc_mem_attach(mctx, &imp->mctx);
234         result = isc_mutex_init(&imp->driverlock);
235         if (result != ISC_R_SUCCESS)
236                 goto cleanup_mctx;
237
238         imp->dbimp = NULL;
239         result = dns_db_register(drivername, dns_sdb_create, imp, mctx,
240                                  &imp->dbimp);
241         if (result != ISC_R_SUCCESS)
242                 goto cleanup_mutex;
243         *sdbimp = imp;
244
245         return (ISC_R_SUCCESS);
246
247  cleanup_mutex:
248         DESTROYLOCK(&imp->driverlock);
249  cleanup_mctx:
250         isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
251         return (result);
252 }
253
254 void
255 dns_sdb_unregister(dns_sdbimplementation_t **sdbimp) {
256         dns_sdbimplementation_t *imp;
257         isc_mem_t *mctx;
258
259         REQUIRE(sdbimp != NULL && *sdbimp != NULL);
260
261         imp = *sdbimp;
262         dns_db_unregister(&imp->dbimp);
263         DESTROYLOCK(&imp->driverlock);
264
265         mctx = imp->mctx;
266         isc_mem_put(mctx, imp, sizeof(dns_sdbimplementation_t));
267         isc_mem_detach(&mctx);
268
269         *sdbimp = NULL;
270 }
271
272 static inline unsigned int
273 initial_size(unsigned int len) {
274         unsigned int size;
275
276         for (size = 1024; size < (64 * 1024); size *= 2)
277                 if (len < size)
278                         return (size);
279         return (65535);
280 }
281
282 isc_result_t
283 dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl,
284                  const unsigned char *rdatap, unsigned int rdlen)
285 {
286         dns_rdatalist_t *rdatalist;
287         dns_rdata_t *rdata;
288         isc_buffer_t *rdatabuf = NULL;
289         isc_result_t result;
290         isc_mem_t *mctx;
291         isc_region_t region;
292
293         mctx = lookup->sdb->common.mctx;
294
295         rdatalist = ISC_LIST_HEAD(lookup->lists);
296         while (rdatalist != NULL) {
297                 if (rdatalist->type == typeval)
298                         break;
299                 rdatalist = ISC_LIST_NEXT(rdatalist, link);
300         }
301
302         if (rdatalist == NULL) {
303                 rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
304                 if (rdatalist == NULL)
305                         return (ISC_R_NOMEMORY);
306                 rdatalist->rdclass = lookup->sdb->common.rdclass;
307                 rdatalist->type = typeval;
308                 rdatalist->covers = 0;
309                 rdatalist->ttl = ttl;
310                 ISC_LIST_INIT(rdatalist->rdata);
311                 ISC_LINK_INIT(rdatalist, link);
312                 ISC_LIST_APPEND(lookup->lists, rdatalist, link);
313         } else
314                 if (rdatalist->ttl != ttl)
315                         return (DNS_R_BADTTL);
316
317         rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
318         if (rdata == NULL)
319                 return (ISC_R_NOMEMORY);
320
321         result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
322         if (result != ISC_R_SUCCESS)
323                 goto failure;
324         DE_CONST(rdatap, region.base);
325         region.length = rdlen;
326         isc_buffer_copyregion(rdatabuf, &region);
327         isc_buffer_usedregion(rdatabuf, &region);
328         dns_rdata_init(rdata);
329         dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
330                              &region);
331         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
332         ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
333         rdata = NULL;
334
335  failure:
336         if (rdata != NULL)
337                 isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
338         return (result);
339 }
340
341
342 isc_result_t
343 dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
344               const char *data)
345 {
346         unsigned int datalen;
347         dns_rdatatype_t typeval;
348         isc_textregion_t r;
349         isc_lex_t *lex = NULL;
350         isc_result_t result;
351         unsigned char *p = NULL;
352         unsigned int size = 0; /* Init to suppress compiler warning */
353         isc_mem_t *mctx;
354         dns_sdbimplementation_t *imp;
355         dns_name_t *origin;
356         isc_buffer_t b;
357         isc_buffer_t rb;
358
359         REQUIRE(VALID_SDBLOOKUP(lookup));
360         REQUIRE(type != NULL);
361         REQUIRE(data != NULL);
362
363         mctx = lookup->sdb->common.mctx;
364
365         DE_CONST(type, r.base);
366         r.length = strlen(type);
367         result = dns_rdatatype_fromtext(&typeval, &r);
368         if (result != ISC_R_SUCCESS)
369                 return (result);
370
371         imp = lookup->sdb->implementation;
372         if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
373                 origin = &lookup->sdb->common.origin;
374         else
375                 origin = dns_rootname;
376
377         result = isc_lex_create(mctx, 64, &lex);
378         if (result != ISC_R_SUCCESS)
379                 goto failure;
380
381         datalen = strlen(data);
382         size = initial_size(datalen);
383         do {
384                 isc_buffer_init(&b, data, datalen);
385                 isc_buffer_add(&b, datalen);
386                 result = isc_lex_openbuffer(lex, &b);
387                 if (result != ISC_R_SUCCESS)
388                         goto failure;
389
390                 if (size >= 65535)
391                         size = 65535;
392                 p = isc_mem_get(mctx, size);
393                 if (p == NULL) {
394                         result = ISC_R_NOMEMORY;
395                         goto failure;
396                 }
397                 isc_buffer_init(&rb, p, size);
398                 result = dns_rdata_fromtext(NULL,
399                                             lookup->sdb->common.rdclass,
400                                             typeval, lex,
401                                             origin, 0,
402                                             mctx, &rb,
403                                             &lookup->callbacks);
404                 if (result != ISC_R_NOSPACE)
405                         break;
406
407                 /*
408                  * Is the RR too big?
409                  */
410                 if (size >= 65535)
411                         break;
412                 isc_mem_put(mctx, p, size);
413                 p = NULL;
414                 size *= 2;
415         } while (result == ISC_R_NOSPACE);
416
417         if (result != ISC_R_SUCCESS)
418                 goto failure;
419
420         result = dns_sdb_putrdata(lookup, typeval, ttl,
421                                   isc_buffer_base(&rb),
422                                   isc_buffer_usedlength(&rb));
423  failure:
424         if (p != NULL)
425                 isc_mem_put(mctx, p, size);
426         if (lex != NULL)
427                 isc_lex_destroy(&lex);
428
429         return (result);
430 }
431
432 static isc_result_t
433 getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
434         dns_name_t *newname, *origin;
435         dns_fixedname_t fnewname;
436         dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
437         dns_sdbimplementation_t *imp = sdb->implementation;
438         dns_sdbnode_t *sdbnode;
439         isc_mem_t *mctx = sdb->common.mctx;
440         isc_buffer_t b;
441         isc_result_t result;
442
443         dns_fixedname_init(&fnewname);
444         newname = dns_fixedname_name(&fnewname);
445
446         if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
447                 origin = &sdb->common.origin;
448         else
449                 origin = dns_rootname;
450         isc_buffer_init(&b, name, strlen(name));
451         isc_buffer_add(&b, strlen(name));
452
453         result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
454         if (result != ISC_R_SUCCESS)
455                 return (result);
456
457         if (allnodes->common.relative_names) {
458                 /* All names are relative to the root */
459                 unsigned int nlabels = dns_name_countlabels(newname);
460                 dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
461         }
462
463         sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
464         if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
465                 sdbnode = NULL;
466                 result = createnode(sdb, &sdbnode);
467                 if (result != ISC_R_SUCCESS)
468                         return (result);
469                 sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
470                 if (sdbnode->name == NULL) {
471                         destroynode(sdbnode);
472                         return (ISC_R_NOMEMORY);
473                 }
474                 dns_name_init(sdbnode->name, NULL);
475                 result = dns_name_dup(newname, mctx, sdbnode->name);
476                 if (result != ISC_R_SUCCESS) {
477                         isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
478                         destroynode(sdbnode);
479                         return (result);
480                 }
481                 ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
482                 if (allnodes->origin == NULL &&
483                     dns_name_equal(newname, &sdb->common.origin))
484                         allnodes->origin = sdbnode;
485         }
486         *nodep = sdbnode;
487         return (ISC_R_SUCCESS);
488 }
489
490 isc_result_t
491 dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
492                    const char *type, dns_ttl_t ttl, const char *data)
493 {
494         isc_result_t result;
495         dns_sdbnode_t *sdbnode = NULL;
496         result = getnode(allnodes, name, &sdbnode);
497         if (result != ISC_R_SUCCESS)
498                 return (result);
499         return (dns_sdb_putrr(sdbnode, type, ttl, data));
500 }
501
502 isc_result_t
503 dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
504                       dns_rdatatype_t type, dns_ttl_t ttl,
505                       const void *rdata, unsigned int rdlen)
506 {
507         isc_result_t result;
508         dns_sdbnode_t *sdbnode = NULL;
509         result = getnode(allnodes, name, &sdbnode);
510         if (result != ISC_R_SUCCESS)
511                 return (result);
512         return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
513 }
514
515 isc_result_t
516 dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
517                isc_uint32_t serial)
518 {
519         char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
520         int n;
521
522         REQUIRE(mname != NULL);
523         REQUIRE(rname != NULL);
524
525         n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
526                      mname, rname, serial,
527                      SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
528                      SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
529         if (n >= (int)sizeof(str) || n < 0)
530                 return (ISC_R_NOSPACE);
531         return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
532 }
533
534 /*
535  * DB routines
536  */
537
538 static void
539 attach(dns_db_t *source, dns_db_t **targetp) {
540         dns_sdb_t *sdb = (dns_sdb_t *) source;
541
542         REQUIRE(VALID_SDB(sdb));
543
544         LOCK(&sdb->lock);
545         REQUIRE(sdb->references > 0);
546         sdb->references++;
547         UNLOCK(&sdb->lock);
548
549         *targetp = source;
550 }
551
552 static void
553 destroy(dns_sdb_t *sdb) {
554         isc_mem_t *mctx;
555         dns_sdbimplementation_t *imp = sdb->implementation;
556
557         mctx = sdb->common.mctx;
558
559         if (imp->methods->destroy != NULL) {
560                 MAYBE_LOCK(sdb);
561                 imp->methods->destroy(sdb->zone, imp->driverdata,
562                                       &sdb->dbdata);
563                 MAYBE_UNLOCK(sdb);
564         }
565
566         isc_mem_free(mctx, sdb->zone);
567         DESTROYLOCK(&sdb->lock);
568
569         sdb->common.magic = 0;
570         sdb->common.impmagic = 0;
571
572         dns_name_free(&sdb->common.origin, mctx);
573
574         isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
575         isc_mem_detach(&mctx);
576 }
577
578 static void
579 detach(dns_db_t **dbp) {
580         dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
581         isc_boolean_t need_destroy = ISC_FALSE;
582
583         REQUIRE(VALID_SDB(sdb));
584         LOCK(&sdb->lock);
585         REQUIRE(sdb->references > 0);
586         sdb->references--;
587         if (sdb->references == 0)
588                 need_destroy = ISC_TRUE;
589         UNLOCK(&sdb->lock);
590
591         if (need_destroy)
592                 destroy(sdb);
593
594         *dbp = NULL;
595 }
596
597 static isc_result_t
598 beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
599         UNUSED(db);
600         UNUSED(addp);
601         UNUSED(dbloadp);
602         return (ISC_R_NOTIMPLEMENTED);
603 }
604
605 static isc_result_t
606 endload(dns_db_t *db, dns_dbload_t **dbloadp) {
607         UNUSED(db);
608         UNUSED(dbloadp);
609         return (ISC_R_NOTIMPLEMENTED);
610 }
611
612 static isc_result_t
613 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename,
614      dns_masterformat_t masterformat) {
615         UNUSED(db);
616         UNUSED(version);
617         UNUSED(filename);
618         UNUSED(masterformat);
619         return (ISC_R_NOTIMPLEMENTED);
620 }
621
622 static void
623 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
624         REQUIRE(versionp != NULL && *versionp == NULL);
625
626         UNUSED(db);
627
628         *versionp = (void *) &dummy;
629         return;
630 }
631
632 static isc_result_t
633 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
634         UNUSED(db);
635         UNUSED(versionp);
636
637         return (ISC_R_NOTIMPLEMENTED);
638 }
639
640 static void
641 attachversion(dns_db_t *db, dns_dbversion_t *source,
642               dns_dbversion_t **targetp)
643 {
644         REQUIRE(source != NULL && source == (void *) &dummy);
645         REQUIRE(targetp != NULL && *targetp == NULL);
646
647         UNUSED(db);
648         *targetp = source;
649         return;
650 }
651
652 static void
653 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
654         REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
655         REQUIRE(commit == ISC_FALSE);
656
657         UNUSED(db);
658         UNUSED(commit);
659
660         *versionp = NULL;
661 }
662
663 static isc_result_t
664 createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
665         dns_sdbnode_t *node;
666         isc_result_t result;
667
668         node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
669         if (node == NULL)
670                 return (ISC_R_NOMEMORY);
671
672         node->sdb = NULL;
673         attach((dns_db_t *)sdb, (dns_db_t **)&node->sdb);
674         ISC_LIST_INIT(node->lists);
675         ISC_LIST_INIT(node->buffers);
676         ISC_LINK_INIT(node, link);
677         node->name = NULL;
678         result = isc_mutex_init(&node->lock);
679         if (result != ISC_R_SUCCESS) {
680                 isc_mem_put(sdb->common.mctx, node, sizeof(dns_sdbnode_t));
681                 return (result);
682         }
683         dns_rdatacallbacks_init(&node->callbacks);
684         node->references = 1;
685         node->magic = SDBLOOKUP_MAGIC;
686
687         *nodep = node;
688         return (ISC_R_SUCCESS);
689 }
690
691 static void
692 destroynode(dns_sdbnode_t *node) {
693         dns_rdatalist_t *list;
694         dns_rdata_t *rdata;
695         isc_buffer_t *b;
696         dns_sdb_t *sdb;
697         isc_mem_t *mctx;
698
699         sdb = node->sdb;
700         mctx = sdb->common.mctx;
701
702         while (!ISC_LIST_EMPTY(node->lists)) {
703                 list = ISC_LIST_HEAD(node->lists);
704                 while (!ISC_LIST_EMPTY(list->rdata)) {
705                         rdata = ISC_LIST_HEAD(list->rdata);
706                         ISC_LIST_UNLINK(list->rdata, rdata, link);
707                         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
708                 }
709                 ISC_LIST_UNLINK(node->lists, list, link);
710                 isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
711         }
712
713         while (!ISC_LIST_EMPTY(node->buffers)) {
714                 b = ISC_LIST_HEAD(node->buffers);
715                 ISC_LIST_UNLINK(node->buffers, b, link);
716                 isc_buffer_free(&b);
717         }
718
719         if (node->name != NULL) {
720                 dns_name_free(node->name, mctx);
721                 isc_mem_put(mctx, node->name, sizeof(dns_name_t));
722         }
723         DESTROYLOCK(&node->lock);
724         node->magic = 0;
725         isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
726         detach((dns_db_t **) (void *)&sdb);
727 }
728
729 static isc_result_t
730 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
731          dns_dbnode_t **nodep)
732 {
733         dns_sdb_t *sdb = (dns_sdb_t *)db;
734         dns_sdbnode_t *node = NULL;
735         isc_result_t result;
736         isc_buffer_t b;
737         char namestr[DNS_NAME_MAXTEXT + 1];
738         isc_boolean_t isorigin;
739         dns_sdbimplementation_t *imp;
740
741         REQUIRE(VALID_SDB(sdb));
742         REQUIRE(create == ISC_FALSE);
743         REQUIRE(nodep != NULL && *nodep == NULL);
744
745         UNUSED(name);
746         UNUSED(create);
747
748         imp = sdb->implementation;
749
750         isc_buffer_init(&b, namestr, sizeof(namestr));
751         if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
752                 dns_name_t relname;
753                 unsigned int labels;
754
755                 labels = dns_name_countlabels(name) -
756                          dns_name_countlabels(&db->origin);
757                 dns_name_init(&relname, NULL);
758                 dns_name_getlabelsequence(name, 0, labels, &relname);
759                 result = dns_name_totext(&relname, ISC_TRUE, &b);
760                 if (result != ISC_R_SUCCESS)
761                         return (result);
762         } else {
763                 result = dns_name_totext(name, ISC_TRUE, &b);
764                 if (result != ISC_R_SUCCESS)
765                         return (result);
766         }
767         isc_buffer_putuint8(&b, 0);
768
769         result = createnode(sdb, &node);
770         if (result != ISC_R_SUCCESS)
771                 return (result);
772
773         isorigin = dns_name_equal(name, &sdb->common.origin);
774
775         MAYBE_LOCK(sdb);
776         result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata, node);
777         MAYBE_UNLOCK(sdb);
778         if (result != ISC_R_SUCCESS &&
779             !(result == ISC_R_NOTFOUND &&
780               isorigin && imp->methods->authority != NULL))
781         {
782                 destroynode(node);
783                 return (result);
784         }
785
786         if (isorigin && imp->methods->authority != NULL) {
787                 MAYBE_LOCK(sdb);
788                 result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
789                 MAYBE_UNLOCK(sdb);
790                 if (result != ISC_R_SUCCESS) {
791                         destroynode(node);
792                         return (result);
793                 }
794         }
795
796         *nodep = node;
797         return (ISC_R_SUCCESS);
798 }
799
800 static isc_result_t
801 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
802      dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
803      dns_dbnode_t **nodep, dns_name_t *foundname,
804      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
805 {
806         dns_sdb_t *sdb = (dns_sdb_t *)db;
807         dns_dbnode_t *node = NULL;
808         dns_fixedname_t fname;
809         dns_rdataset_t xrdataset;
810         dns_name_t *xname;
811         unsigned int nlabels, olabels;
812         isc_result_t result;
813         unsigned int i;
814
815         REQUIRE(VALID_SDB(sdb));
816         REQUIRE(nodep == NULL || *nodep == NULL);
817         REQUIRE(version == NULL || version == (void *) &dummy);
818
819         UNUSED(options);
820         UNUSED(sdb);
821
822         if (!dns_name_issubdomain(name, &db->origin))
823                 return (DNS_R_NXDOMAIN);
824
825         olabels = dns_name_countlabels(&db->origin);
826         nlabels = dns_name_countlabels(name);
827
828         dns_fixedname_init(&fname);
829         xname = dns_fixedname_name(&fname);
830
831         if (rdataset == NULL) {
832                 dns_rdataset_init(&xrdataset);
833                 rdataset = &xrdataset;
834         }
835
836         result = DNS_R_NXDOMAIN;
837
838         for (i = olabels; i <= nlabels; i++) {
839                 /*
840                  * Unless this is an explicit lookup at the origin, don't
841                  * look at the origin.
842                  */
843                 if (i == olabels && i != nlabels)
844                         continue;
845
846                 /*
847                  * Look up the next label.
848                  */
849                 dns_name_getlabelsequence(name, nlabels - i, i, xname);
850                 result = findnode(db, xname, ISC_FALSE, &node);
851                 if (result != ISC_R_SUCCESS) {
852                         result = DNS_R_NXDOMAIN;
853                         continue;
854                 }
855
856                 /*
857                  * Look for a DNAME at the current label, unless this is
858                  * the qname.
859                  */
860                 if (i < nlabels) {
861                         result = findrdataset(db, node, version,
862                                               dns_rdatatype_dname,
863                                               0, now, rdataset, sigrdataset);
864                         if (result == ISC_R_SUCCESS) {
865                                 result = DNS_R_DNAME;
866                                 break;
867                         }
868                 }
869
870                 /*
871                  * Look for an NS at the current label, unless this is the
872                  * origin or glue is ok.
873                  */
874                 if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
875                         result = findrdataset(db, node, version,
876                                               dns_rdatatype_ns,
877                                               0, now, rdataset, sigrdataset);
878                         if (result == ISC_R_SUCCESS) {
879                                 if (i == nlabels && type == dns_rdatatype_any)
880                                 {
881                                         result = DNS_R_ZONECUT;
882                                         dns_rdataset_disassociate(rdataset);
883                                         if (sigrdataset != NULL)
884                                                 dns_rdataset_disassociate
885                                                                 (sigrdataset);
886                                 } else
887                                         result = DNS_R_DELEGATION;
888                                 break;
889                         }
890                 }
891
892                 /*
893                  * If the current name is not the qname, add another label
894                  * and try again.
895                  */
896                 if (i < nlabels) {
897                         destroynode(node);
898                         node = NULL;
899                         continue;
900                 }
901
902                 /*
903                  * If we're looking for ANY, we're done.
904                  */
905                 if (type == dns_rdatatype_any) {
906                         result = ISC_R_SUCCESS;
907                         break;
908                 }
909
910                 /*
911                  * Look for the qtype.
912                  */
913                 result = findrdataset(db, node, version, type,
914                                       0, now, rdataset, sigrdataset);
915                 if (result == ISC_R_SUCCESS)
916                         break;
917
918                 /*
919                  * Look for a CNAME
920                  */
921                 if (type != dns_rdatatype_cname) {
922                         result = findrdataset(db, node, version,
923                                               dns_rdatatype_cname,
924                                               0, now, rdataset, sigrdataset);
925                         if (result == ISC_R_SUCCESS) {
926                                 result = DNS_R_CNAME;
927                                 break;
928                         }
929                 }
930
931                 result = DNS_R_NXRRSET;
932                 break;
933         }
934
935         if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
936                 dns_rdataset_disassociate(rdataset);
937
938         if (foundname != NULL) {
939                 isc_result_t xresult;
940
941                 xresult = dns_name_copy(xname, foundname, NULL);
942                 if (xresult != ISC_R_SUCCESS) {
943                         if (node != NULL)
944                                 destroynode(node);
945                         if (dns_rdataset_isassociated(rdataset))
946                                 dns_rdataset_disassociate(rdataset);
947                         return (DNS_R_BADDB);
948                 }
949         }
950
951         if (nodep != NULL)
952                 *nodep = node;
953         else if (node != NULL)
954                 detachnode(db, &node);
955
956         return (result);
957 }
958
959 static isc_result_t
960 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
961             isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
962             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
963 {
964         UNUSED(db);
965         UNUSED(name);
966         UNUSED(options);
967         UNUSED(now);
968         UNUSED(nodep);
969         UNUSED(foundname);
970         UNUSED(rdataset);
971         UNUSED(sigrdataset);
972
973         return (ISC_R_NOTIMPLEMENTED);
974 }
975
976 static void
977 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
978         dns_sdb_t *sdb = (dns_sdb_t *)db;
979         dns_sdbnode_t *node = (dns_sdbnode_t *)source;
980
981         REQUIRE(VALID_SDB(sdb));
982
983         UNUSED(sdb);
984
985         LOCK(&node->lock);
986         INSIST(node->references > 0);
987         node->references++;
988         INSIST(node->references != 0);          /* Catch overflow. */
989         UNLOCK(&node->lock);
990
991         *targetp = source;
992 }
993
994 static void
995 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
996         dns_sdb_t *sdb = (dns_sdb_t *)db;
997         dns_sdbnode_t *node;
998         isc_boolean_t need_destroy = ISC_FALSE;
999
1000         REQUIRE(VALID_SDB(sdb));
1001         REQUIRE(targetp != NULL && *targetp != NULL);
1002
1003         UNUSED(sdb);
1004
1005         node = (dns_sdbnode_t *)(*targetp);
1006
1007         LOCK(&node->lock);
1008         INSIST(node->references > 0);
1009         node->references--;
1010         if (node->references == 0)
1011                 need_destroy = ISC_TRUE;
1012         UNLOCK(&node->lock);
1013
1014         if (need_destroy)
1015                 destroynode(node);
1016
1017         *targetp = NULL;
1018 }
1019
1020 static isc_result_t
1021 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1022         UNUSED(db);
1023         UNUSED(node);
1024         UNUSED(now);
1025         INSIST(0);
1026         return (ISC_R_UNEXPECTED);
1027 }
1028
1029 static void
1030 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1031         UNUSED(db);
1032         UNUSED(node);
1033         UNUSED(out);
1034         return;
1035 }
1036
1037 static isc_result_t
1038 createiterator(dns_db_t *db, isc_boolean_t relative_names,
1039                dns_dbiterator_t **iteratorp)
1040 {
1041         dns_sdb_t *sdb = (dns_sdb_t *)db;
1042         sdb_dbiterator_t *sdbiter;
1043         dns_sdbimplementation_t *imp = sdb->implementation;
1044         isc_result_t result;
1045
1046         REQUIRE(VALID_SDB(sdb));
1047
1048         if (imp->methods->allnodes == NULL)
1049                 return (ISC_R_NOTIMPLEMENTED);
1050
1051         sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1052         if (sdbiter == NULL)
1053                 return (ISC_R_NOMEMORY);
1054
1055         sdbiter->common.methods = &dbiterator_methods;
1056         sdbiter->common.db = NULL;
1057         dns_db_attach(db, &sdbiter->common.db);
1058         sdbiter->common.relative_names = relative_names;
1059         sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1060         ISC_LIST_INIT(sdbiter->nodelist);
1061         sdbiter->current = NULL;
1062         sdbiter->origin = NULL;
1063
1064         MAYBE_LOCK(sdb);
1065         result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1066         MAYBE_UNLOCK(sdb);
1067         if (result != ISC_R_SUCCESS) {
1068                 dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1069                 return (result);
1070         }
1071
1072         if (sdbiter->origin != NULL) {
1073                 ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1074                 ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1075         }
1076
1077         *iteratorp = (dns_dbiterator_t *)sdbiter;
1078
1079         return (ISC_R_SUCCESS);
1080 }
1081
1082 static isc_result_t
1083 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1084              dns_rdatatype_t type, dns_rdatatype_t covers,
1085              isc_stdtime_t now, dns_rdataset_t *rdataset,
1086              dns_rdataset_t *sigrdataset)
1087 {
1088         dns_rdatalist_t *list;
1089         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1090
1091         REQUIRE(VALID_SDBNODE(node));
1092
1093         UNUSED(db);
1094         UNUSED(version);
1095         UNUSED(covers);
1096         UNUSED(now);
1097         UNUSED(sigrdataset);
1098
1099         if (type == dns_rdatatype_rrsig)
1100                 return (ISC_R_NOTIMPLEMENTED);
1101
1102         list = ISC_LIST_HEAD(sdbnode->lists);
1103         while (list != NULL) {
1104                 if (list->type == type)
1105                         break;
1106                 list = ISC_LIST_NEXT(list, link);
1107         }
1108         if (list == NULL)
1109                 return (ISC_R_NOTFOUND);
1110
1111         list_tordataset(list, db, node, rdataset);
1112
1113         return (ISC_R_SUCCESS);
1114 }
1115
1116 static isc_result_t
1117 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1118              isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1119 {
1120         sdb_rdatasetiter_t *iterator;
1121
1122         REQUIRE(version == NULL || version == &dummy);
1123
1124         UNUSED(version);
1125         UNUSED(now);
1126
1127         iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1128         if (iterator == NULL)
1129                 return (ISC_R_NOMEMORY);
1130
1131         iterator->common.magic = DNS_RDATASETITER_MAGIC;
1132         iterator->common.methods = &rdatasetiter_methods;
1133         iterator->common.db = db;
1134         iterator->common.node = NULL;
1135         attachnode(db, node, &iterator->common.node);
1136         iterator->common.version = version;
1137         iterator->common.now = now;
1138
1139         *iteratorp = (dns_rdatasetiter_t *)iterator;
1140
1141         return (ISC_R_SUCCESS);
1142 }
1143
1144 static isc_result_t
1145 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1146             isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1147             dns_rdataset_t *addedrdataset)
1148 {
1149         UNUSED(db);
1150         UNUSED(node);
1151         UNUSED(version);
1152         UNUSED(now);
1153         UNUSED(rdataset);
1154         UNUSED(options);
1155         UNUSED(addedrdataset);
1156
1157         return (ISC_R_NOTIMPLEMENTED);
1158 }
1159
1160 static isc_result_t
1161 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1162                  dns_rdataset_t *rdataset, unsigned int options,
1163                  dns_rdataset_t *newrdataset)
1164 {
1165         UNUSED(db);
1166         UNUSED(node);
1167         UNUSED(version);
1168         UNUSED(rdataset);
1169         UNUSED(options);
1170         UNUSED(newrdataset);
1171
1172         return (ISC_R_NOTIMPLEMENTED);
1173 }
1174
1175 static isc_result_t
1176 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1177                dns_rdatatype_t type, dns_rdatatype_t covers)
1178 {
1179         UNUSED(db);
1180         UNUSED(node);
1181         UNUSED(version);
1182         UNUSED(type);
1183         UNUSED(covers);
1184
1185         return (ISC_R_NOTIMPLEMENTED);
1186 }
1187
1188 static isc_boolean_t
1189 issecure(dns_db_t *db) {
1190         UNUSED(db);
1191
1192         return (ISC_FALSE);
1193 }
1194
1195 static unsigned int
1196 nodecount(dns_db_t *db) {
1197         UNUSED(db);
1198
1199         return (0);
1200 }
1201
1202 static isc_boolean_t
1203 ispersistent(dns_db_t *db) {
1204         UNUSED(db);
1205         return (ISC_TRUE);
1206 }
1207
1208 static void
1209 overmem(dns_db_t *db, isc_boolean_t overmem) {
1210         UNUSED(db);
1211         UNUSED(overmem);
1212 }
1213
1214 static void
1215 settask(dns_db_t *db, isc_task_t *task) {
1216         UNUSED(db);
1217         UNUSED(task);
1218 }
1219
1220
1221 static dns_dbmethods_t sdb_methods = {
1222         attach,
1223         detach,
1224         beginload,
1225         endload,
1226         dump,
1227         currentversion,
1228         newversion,
1229         attachversion,
1230         closeversion,
1231         findnode,
1232         find,
1233         findzonecut,
1234         attachnode,
1235         detachnode,
1236         expirenode,
1237         printnode,
1238         createiterator,
1239         findrdataset,
1240         allrdatasets,
1241         addrdataset,
1242         subtractrdataset,
1243         deleterdataset,
1244         issecure,
1245         nodecount,
1246         ispersistent,
1247         overmem,
1248         settask,
1249         NULL
1250 };
1251
1252 static isc_result_t
1253 dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1254                dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1255                void *driverarg, dns_db_t **dbp)
1256 {
1257         dns_sdb_t *sdb;
1258         isc_result_t result;
1259         char zonestr[DNS_NAME_MAXTEXT + 1];
1260         isc_buffer_t b;
1261         dns_sdbimplementation_t *imp;
1262
1263         REQUIRE(driverarg != NULL);
1264
1265         imp = driverarg;
1266
1267         if (type != dns_dbtype_zone)
1268                 return (ISC_R_NOTIMPLEMENTED);
1269
1270         sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1271         if (sdb == NULL)
1272                 return (ISC_R_NOMEMORY);
1273         memset(sdb, 0, sizeof(dns_sdb_t));
1274
1275         dns_name_init(&sdb->common.origin, NULL);
1276         sdb->common.attributes = 0;
1277         sdb->common.methods = &sdb_methods;
1278         sdb->common.rdclass = rdclass;
1279         sdb->common.mctx = NULL;
1280         sdb->implementation = imp;
1281
1282         isc_mem_attach(mctx, &sdb->common.mctx);
1283
1284         result = isc_mutex_init(&sdb->lock);
1285         if (result != ISC_R_SUCCESS)
1286                 goto cleanup_mctx;
1287
1288         result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1289         if (result != ISC_R_SUCCESS)
1290                 goto cleanup_lock;
1291
1292         isc_buffer_init(&b, zonestr, sizeof(zonestr));
1293         result = dns_name_totext(origin, ISC_TRUE, &b);
1294         if (result != ISC_R_SUCCESS)
1295                 goto cleanup_origin;
1296         isc_buffer_putuint8(&b, 0);
1297
1298         sdb->zone = isc_mem_strdup(mctx, zonestr);
1299         if (sdb->zone == NULL) {
1300                 result = ISC_R_NOMEMORY;
1301                 goto cleanup_origin;
1302         }
1303
1304         sdb->dbdata = NULL;
1305         if (imp->methods->create != NULL) {
1306                 MAYBE_LOCK(sdb);
1307                 result = imp->methods->create(sdb->zone, argc, argv,
1308                                               imp->driverdata, &sdb->dbdata);
1309                 MAYBE_UNLOCK(sdb);
1310                 if (result != ISC_R_SUCCESS)
1311                         goto cleanup_zonestr;
1312         }
1313
1314         sdb->references = 1;
1315
1316         sdb->common.magic = DNS_DB_MAGIC;
1317         sdb->common.impmagic = SDB_MAGIC;
1318
1319         *dbp = (dns_db_t *)sdb;
1320
1321         return (ISC_R_SUCCESS);
1322
1323  cleanup_zonestr:
1324         isc_mem_free(mctx, sdb->zone);
1325  cleanup_origin:
1326         dns_name_free(&sdb->common.origin, mctx);
1327  cleanup_lock:
1328         isc_mutex_destroy(&sdb->lock);
1329  cleanup_mctx:
1330         isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1331         isc_mem_detach(&mctx);
1332
1333         return (result);
1334 }
1335
1336
1337 /*
1338  * Rdataset Methods
1339  */
1340
1341 static void
1342 disassociate(dns_rdataset_t *rdataset) {
1343         dns_dbnode_t *node = rdataset->private5;
1344         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1345         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1346
1347         detachnode(db, &node);
1348         isc__rdatalist_disassociate(rdataset);
1349 }
1350
1351 static void
1352 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1353         dns_dbnode_t *node = source->private5;
1354         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1355         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1356         dns_dbnode_t *tempdb = NULL;
1357
1358         isc__rdatalist_clone(source, target);
1359         attachnode(db, node, &tempdb);
1360         source->private5 = tempdb;
1361 }
1362
1363 static dns_rdatasetmethods_t methods = {
1364         disassociate,
1365         isc__rdatalist_first,
1366         isc__rdatalist_next,
1367         isc__rdatalist_current,
1368         rdataset_clone,
1369         isc__rdatalist_count,
1370         isc__rdatalist_addnoqname,
1371         isc__rdatalist_getnoqname,
1372         NULL,
1373         NULL,
1374         NULL
1375 };
1376
1377 static void
1378 list_tordataset(dns_rdatalist_t *rdatalist,
1379                 dns_db_t *db, dns_dbnode_t *node,
1380                 dns_rdataset_t *rdataset)
1381 {
1382         /*
1383          * The sdb rdataset is an rdatalist with some additions.
1384          *      - private1 & private2 are used by the rdatalist.
1385          *      - private3 & private 4 are unused.
1386          *      - private5 is the node.
1387          */
1388
1389         /* This should never fail. */
1390         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1391                       ISC_R_SUCCESS);
1392
1393         rdataset->methods = &methods;
1394         dns_db_attachnode(db, node, &rdataset->private5);
1395 }
1396
1397 /*
1398  * Database Iterator Methods
1399  */
1400 static void
1401 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1402         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1403         dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1404
1405         while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1406                 dns_sdbnode_t *node;
1407                 node = ISC_LIST_HEAD(sdbiter->nodelist);
1408                 ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1409                 destroynode(node);
1410         }
1411
1412         dns_db_detach(&sdbiter->common.db);
1413         isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1414
1415         *iteratorp = NULL;
1416 }
1417
1418 static isc_result_t
1419 dbiterator_first(dns_dbiterator_t *iterator) {
1420         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1421
1422         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1423         if (sdbiter->current == NULL)
1424                 return (ISC_R_NOMORE);
1425         else
1426                 return (ISC_R_SUCCESS);
1427 }
1428
1429 static isc_result_t
1430 dbiterator_last(dns_dbiterator_t *iterator) {
1431         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1432
1433         sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1434         if (sdbiter->current == NULL)
1435                 return (ISC_R_NOMORE);
1436         else
1437                 return (ISC_R_SUCCESS);
1438 }
1439
1440 static isc_result_t
1441 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1442         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1443
1444         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1445         while (sdbiter->current != NULL)
1446                 if (dns_name_equal(sdbiter->current->name, name))
1447                         return (ISC_R_SUCCESS);
1448         return (ISC_R_NOTFOUND);
1449 }
1450
1451 static isc_result_t
1452 dbiterator_prev(dns_dbiterator_t *iterator) {
1453         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1454
1455         sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1456         if (sdbiter->current == NULL)
1457                 return (ISC_R_NOMORE);
1458         else
1459                 return (ISC_R_SUCCESS);
1460 }
1461
1462 static isc_result_t
1463 dbiterator_next(dns_dbiterator_t *iterator) {
1464         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1465
1466         sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1467         if (sdbiter->current == NULL)
1468                 return (ISC_R_NOMORE);
1469         else
1470                 return (ISC_R_SUCCESS);
1471 }
1472
1473 static isc_result_t
1474 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1475                    dns_name_t *name)
1476 {
1477         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1478
1479         attachnode(iterator->db, sdbiter->current, nodep);
1480         if (name != NULL)
1481                 return (dns_name_copy(sdbiter->current->name, name, NULL));
1482         return (ISC_R_SUCCESS);
1483 }
1484
1485 static isc_result_t
1486 dbiterator_pause(dns_dbiterator_t *iterator) {
1487         UNUSED(iterator);
1488         return (ISC_R_SUCCESS);
1489 }
1490
1491 static isc_result_t
1492 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1493         UNUSED(iterator);
1494         return (dns_name_copy(dns_rootname, name, NULL));
1495 }
1496
1497 /*
1498  * Rdataset Iterator Methods
1499  */
1500
1501 static void
1502 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1503         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1504         detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1505         isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1506                     sizeof(sdb_rdatasetiter_t));
1507         *iteratorp = NULL;
1508 }
1509
1510 static isc_result_t
1511 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1512         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1513         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1514
1515         if (ISC_LIST_EMPTY(sdbnode->lists))
1516                 return (ISC_R_NOMORE);
1517         sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1518         return (ISC_R_SUCCESS);
1519 }
1520
1521 static isc_result_t
1522 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1523         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1524
1525         sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1526         if (sdbiterator->current == NULL)
1527                 return (ISC_R_NOMORE);
1528         else
1529                 return (ISC_R_SUCCESS);
1530 }
1531
1532 static void
1533 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1534         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1535
1536         list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1537                         rdataset);
1538 }