Merge branch 'vendor/OPENSSH'
[dragonfly.git] / contrib / bind / lib / dns / sdb.c
1 /*
2  * Copyright (C) 2004-2009  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.59.94.8 2009/06/26 06:23:47 marka 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_isassociated
885                                                         (sigrdataset)) {
886                                                 dns_rdataset_disassociate
887                                                                 (sigrdataset);
888                                         }
889                                 } else
890                                         result = DNS_R_DELEGATION;
891                                 break;
892                         }
893                 }
894
895                 /*
896                  * If the current name is not the qname, add another label
897                  * and try again.
898                  */
899                 if (i < nlabels) {
900                         destroynode(node);
901                         node = NULL;
902                         continue;
903                 }
904
905                 /*
906                  * If we're looking for ANY, we're done.
907                  */
908                 if (type == dns_rdatatype_any) {
909                         result = ISC_R_SUCCESS;
910                         break;
911                 }
912
913                 /*
914                  * Look for the qtype.
915                  */
916                 result = findrdataset(db, node, version, type,
917                                       0, now, rdataset, sigrdataset);
918                 if (result == ISC_R_SUCCESS)
919                         break;
920
921                 /*
922                  * Look for a CNAME
923                  */
924                 if (type != dns_rdatatype_cname) {
925                         result = findrdataset(db, node, version,
926                                               dns_rdatatype_cname,
927                                               0, now, rdataset, sigrdataset);
928                         if (result == ISC_R_SUCCESS) {
929                                 result = DNS_R_CNAME;
930                                 break;
931                         }
932                 }
933
934                 result = DNS_R_NXRRSET;
935                 break;
936         }
937
938         if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
939                 dns_rdataset_disassociate(rdataset);
940
941         if (foundname != NULL) {
942                 isc_result_t xresult;
943
944                 xresult = dns_name_copy(xname, foundname, NULL);
945                 if (xresult != ISC_R_SUCCESS) {
946                         if (node != NULL)
947                                 destroynode(node);
948                         if (dns_rdataset_isassociated(rdataset))
949                                 dns_rdataset_disassociate(rdataset);
950                         return (DNS_R_BADDB);
951                 }
952         }
953
954         if (nodep != NULL)
955                 *nodep = node;
956         else if (node != NULL)
957                 detachnode(db, &node);
958
959         return (result);
960 }
961
962 static isc_result_t
963 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
964             isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
965             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
966 {
967         UNUSED(db);
968         UNUSED(name);
969         UNUSED(options);
970         UNUSED(now);
971         UNUSED(nodep);
972         UNUSED(foundname);
973         UNUSED(rdataset);
974         UNUSED(sigrdataset);
975
976         return (ISC_R_NOTIMPLEMENTED);
977 }
978
979 static void
980 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
981         dns_sdb_t *sdb = (dns_sdb_t *)db;
982         dns_sdbnode_t *node = (dns_sdbnode_t *)source;
983
984         REQUIRE(VALID_SDB(sdb));
985
986         UNUSED(sdb);
987
988         LOCK(&node->lock);
989         INSIST(node->references > 0);
990         node->references++;
991         INSIST(node->references != 0);          /* Catch overflow. */
992         UNLOCK(&node->lock);
993
994         *targetp = source;
995 }
996
997 static void
998 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
999         dns_sdb_t *sdb = (dns_sdb_t *)db;
1000         dns_sdbnode_t *node;
1001         isc_boolean_t need_destroy = ISC_FALSE;
1002
1003         REQUIRE(VALID_SDB(sdb));
1004         REQUIRE(targetp != NULL && *targetp != NULL);
1005
1006         UNUSED(sdb);
1007
1008         node = (dns_sdbnode_t *)(*targetp);
1009
1010         LOCK(&node->lock);
1011         INSIST(node->references > 0);
1012         node->references--;
1013         if (node->references == 0)
1014                 need_destroy = ISC_TRUE;
1015         UNLOCK(&node->lock);
1016
1017         if (need_destroy)
1018                 destroynode(node);
1019
1020         *targetp = NULL;
1021 }
1022
1023 static isc_result_t
1024 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1025         UNUSED(db);
1026         UNUSED(node);
1027         UNUSED(now);
1028         INSIST(0);
1029         return (ISC_R_UNEXPECTED);
1030 }
1031
1032 static void
1033 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1034         UNUSED(db);
1035         UNUSED(node);
1036         UNUSED(out);
1037         return;
1038 }
1039
1040 static isc_result_t
1041 createiterator(dns_db_t *db, isc_boolean_t relative_names,
1042                dns_dbiterator_t **iteratorp)
1043 {
1044         dns_sdb_t *sdb = (dns_sdb_t *)db;
1045         sdb_dbiterator_t *sdbiter;
1046         dns_sdbimplementation_t *imp = sdb->implementation;
1047         isc_result_t result;
1048
1049         REQUIRE(VALID_SDB(sdb));
1050
1051         if (imp->methods->allnodes == NULL)
1052                 return (ISC_R_NOTIMPLEMENTED);
1053
1054         sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1055         if (sdbiter == NULL)
1056                 return (ISC_R_NOMEMORY);
1057
1058         sdbiter->common.methods = &dbiterator_methods;
1059         sdbiter->common.db = NULL;
1060         dns_db_attach(db, &sdbiter->common.db);
1061         sdbiter->common.relative_names = relative_names;
1062         sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1063         ISC_LIST_INIT(sdbiter->nodelist);
1064         sdbiter->current = NULL;
1065         sdbiter->origin = NULL;
1066
1067         MAYBE_LOCK(sdb);
1068         result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1069         MAYBE_UNLOCK(sdb);
1070         if (result != ISC_R_SUCCESS) {
1071                 dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1072                 return (result);
1073         }
1074
1075         if (sdbiter->origin != NULL) {
1076                 ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1077                 ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1078         }
1079
1080         *iteratorp = (dns_dbiterator_t *)sdbiter;
1081
1082         return (ISC_R_SUCCESS);
1083 }
1084
1085 static isc_result_t
1086 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1087              dns_rdatatype_t type, dns_rdatatype_t covers,
1088              isc_stdtime_t now, dns_rdataset_t *rdataset,
1089              dns_rdataset_t *sigrdataset)
1090 {
1091         dns_rdatalist_t *list;
1092         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1093
1094         REQUIRE(VALID_SDBNODE(node));
1095
1096         UNUSED(db);
1097         UNUSED(version);
1098         UNUSED(covers);
1099         UNUSED(now);
1100         UNUSED(sigrdataset);
1101
1102         if (type == dns_rdatatype_rrsig)
1103                 return (ISC_R_NOTIMPLEMENTED);
1104
1105         list = ISC_LIST_HEAD(sdbnode->lists);
1106         while (list != NULL) {
1107                 if (list->type == type)
1108                         break;
1109                 list = ISC_LIST_NEXT(list, link);
1110         }
1111         if (list == NULL)
1112                 return (ISC_R_NOTFOUND);
1113
1114         list_tordataset(list, db, node, rdataset);
1115
1116         return (ISC_R_SUCCESS);
1117 }
1118
1119 static isc_result_t
1120 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1121              isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1122 {
1123         sdb_rdatasetiter_t *iterator;
1124
1125         REQUIRE(version == NULL || version == &dummy);
1126
1127         UNUSED(version);
1128         UNUSED(now);
1129
1130         iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1131         if (iterator == NULL)
1132                 return (ISC_R_NOMEMORY);
1133
1134         iterator->common.magic = DNS_RDATASETITER_MAGIC;
1135         iterator->common.methods = &rdatasetiter_methods;
1136         iterator->common.db = db;
1137         iterator->common.node = NULL;
1138         attachnode(db, node, &iterator->common.node);
1139         iterator->common.version = version;
1140         iterator->common.now = now;
1141
1142         *iteratorp = (dns_rdatasetiter_t *)iterator;
1143
1144         return (ISC_R_SUCCESS);
1145 }
1146
1147 static isc_result_t
1148 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1149             isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1150             dns_rdataset_t *addedrdataset)
1151 {
1152         UNUSED(db);
1153         UNUSED(node);
1154         UNUSED(version);
1155         UNUSED(now);
1156         UNUSED(rdataset);
1157         UNUSED(options);
1158         UNUSED(addedrdataset);
1159
1160         return (ISC_R_NOTIMPLEMENTED);
1161 }
1162
1163 static isc_result_t
1164 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1165                  dns_rdataset_t *rdataset, unsigned int options,
1166                  dns_rdataset_t *newrdataset)
1167 {
1168         UNUSED(db);
1169         UNUSED(node);
1170         UNUSED(version);
1171         UNUSED(rdataset);
1172         UNUSED(options);
1173         UNUSED(newrdataset);
1174
1175         return (ISC_R_NOTIMPLEMENTED);
1176 }
1177
1178 static isc_result_t
1179 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1180                dns_rdatatype_t type, dns_rdatatype_t covers)
1181 {
1182         UNUSED(db);
1183         UNUSED(node);
1184         UNUSED(version);
1185         UNUSED(type);
1186         UNUSED(covers);
1187
1188         return (ISC_R_NOTIMPLEMENTED);
1189 }
1190
1191 static isc_boolean_t
1192 issecure(dns_db_t *db) {
1193         UNUSED(db);
1194
1195         return (ISC_FALSE);
1196 }
1197
1198 static unsigned int
1199 nodecount(dns_db_t *db) {
1200         UNUSED(db);
1201
1202         return (0);
1203 }
1204
1205 static isc_boolean_t
1206 ispersistent(dns_db_t *db) {
1207         UNUSED(db);
1208         return (ISC_TRUE);
1209 }
1210
1211 static void
1212 overmem(dns_db_t *db, isc_boolean_t overmem) {
1213         UNUSED(db);
1214         UNUSED(overmem);
1215 }
1216
1217 static void
1218 settask(dns_db_t *db, isc_task_t *task) {
1219         UNUSED(db);
1220         UNUSED(task);
1221 }
1222
1223
1224 static dns_dbmethods_t sdb_methods = {
1225         attach,
1226         detach,
1227         beginload,
1228         endload,
1229         dump,
1230         currentversion,
1231         newversion,
1232         attachversion,
1233         closeversion,
1234         findnode,
1235         find,
1236         findzonecut,
1237         attachnode,
1238         detachnode,
1239         expirenode,
1240         printnode,
1241         createiterator,
1242         findrdataset,
1243         allrdatasets,
1244         addrdataset,
1245         subtractrdataset,
1246         deleterdataset,
1247         issecure,
1248         nodecount,
1249         ispersistent,
1250         overmem,
1251         settask,
1252         NULL,
1253         NULL,
1254         NULL
1255 };
1256
1257 static isc_result_t
1258 dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1259                dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1260                void *driverarg, dns_db_t **dbp)
1261 {
1262         dns_sdb_t *sdb;
1263         isc_result_t result;
1264         char zonestr[DNS_NAME_MAXTEXT + 1];
1265         isc_buffer_t b;
1266         dns_sdbimplementation_t *imp;
1267
1268         REQUIRE(driverarg != NULL);
1269
1270         imp = driverarg;
1271
1272         if (type != dns_dbtype_zone)
1273                 return (ISC_R_NOTIMPLEMENTED);
1274
1275         sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1276         if (sdb == NULL)
1277                 return (ISC_R_NOMEMORY);
1278         memset(sdb, 0, sizeof(dns_sdb_t));
1279
1280         dns_name_init(&sdb->common.origin, NULL);
1281         sdb->common.attributes = 0;
1282         sdb->common.methods = &sdb_methods;
1283         sdb->common.rdclass = rdclass;
1284         sdb->common.mctx = NULL;
1285         sdb->implementation = imp;
1286
1287         isc_mem_attach(mctx, &sdb->common.mctx);
1288
1289         result = isc_mutex_init(&sdb->lock);
1290         if (result != ISC_R_SUCCESS)
1291                 goto cleanup_mctx;
1292
1293         result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1294         if (result != ISC_R_SUCCESS)
1295                 goto cleanup_lock;
1296
1297         isc_buffer_init(&b, zonestr, sizeof(zonestr));
1298         result = dns_name_totext(origin, ISC_TRUE, &b);
1299         if (result != ISC_R_SUCCESS)
1300                 goto cleanup_origin;
1301         isc_buffer_putuint8(&b, 0);
1302
1303         sdb->zone = isc_mem_strdup(mctx, zonestr);
1304         if (sdb->zone == NULL) {
1305                 result = ISC_R_NOMEMORY;
1306                 goto cleanup_origin;
1307         }
1308
1309         sdb->dbdata = NULL;
1310         if (imp->methods->create != NULL) {
1311                 MAYBE_LOCK(sdb);
1312                 result = imp->methods->create(sdb->zone, argc, argv,
1313                                               imp->driverdata, &sdb->dbdata);
1314                 MAYBE_UNLOCK(sdb);
1315                 if (result != ISC_R_SUCCESS)
1316                         goto cleanup_zonestr;
1317         }
1318
1319         sdb->references = 1;
1320
1321         sdb->common.magic = DNS_DB_MAGIC;
1322         sdb->common.impmagic = SDB_MAGIC;
1323
1324         *dbp = (dns_db_t *)sdb;
1325
1326         return (ISC_R_SUCCESS);
1327
1328  cleanup_zonestr:
1329         isc_mem_free(mctx, sdb->zone);
1330  cleanup_origin:
1331         dns_name_free(&sdb->common.origin, mctx);
1332  cleanup_lock:
1333         isc_mutex_destroy(&sdb->lock);
1334  cleanup_mctx:
1335         isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1336         isc_mem_detach(&mctx);
1337
1338         return (result);
1339 }
1340
1341
1342 /*
1343  * Rdataset Methods
1344  */
1345
1346 static void
1347 disassociate(dns_rdataset_t *rdataset) {
1348         dns_dbnode_t *node = rdataset->private5;
1349         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1350         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1351
1352         detachnode(db, &node);
1353         isc__rdatalist_disassociate(rdataset);
1354 }
1355
1356 static void
1357 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1358         dns_dbnode_t *node = source->private5;
1359         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1360         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1361         dns_dbnode_t *tempdb = NULL;
1362
1363         isc__rdatalist_clone(source, target);
1364         attachnode(db, node, &tempdb);
1365         source->private5 = tempdb;
1366 }
1367
1368 static dns_rdatasetmethods_t methods = {
1369         disassociate,
1370         isc__rdatalist_first,
1371         isc__rdatalist_next,
1372         isc__rdatalist_current,
1373         rdataset_clone,
1374         isc__rdatalist_count,
1375         isc__rdatalist_addnoqname,
1376         isc__rdatalist_getnoqname,
1377         NULL,
1378         NULL,
1379         NULL
1380 };
1381
1382 static void
1383 list_tordataset(dns_rdatalist_t *rdatalist,
1384                 dns_db_t *db, dns_dbnode_t *node,
1385                 dns_rdataset_t *rdataset)
1386 {
1387         /*
1388          * The sdb rdataset is an rdatalist with some additions.
1389          *      - private1 & private2 are used by the rdatalist.
1390          *      - private3 & private 4 are unused.
1391          *      - private5 is the node.
1392          */
1393
1394         /* This should never fail. */
1395         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1396                       ISC_R_SUCCESS);
1397
1398         rdataset->methods = &methods;
1399         dns_db_attachnode(db, node, &rdataset->private5);
1400 }
1401
1402 /*
1403  * Database Iterator Methods
1404  */
1405 static void
1406 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1407         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1408         dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1409
1410         while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1411                 dns_sdbnode_t *node;
1412                 node = ISC_LIST_HEAD(sdbiter->nodelist);
1413                 ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1414                 destroynode(node);
1415         }
1416
1417         dns_db_detach(&sdbiter->common.db);
1418         isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1419
1420         *iteratorp = NULL;
1421 }
1422
1423 static isc_result_t
1424 dbiterator_first(dns_dbiterator_t *iterator) {
1425         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1426
1427         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1428         if (sdbiter->current == NULL)
1429                 return (ISC_R_NOMORE);
1430         else
1431                 return (ISC_R_SUCCESS);
1432 }
1433
1434 static isc_result_t
1435 dbiterator_last(dns_dbiterator_t *iterator) {
1436         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1437
1438         sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1439         if (sdbiter->current == NULL)
1440                 return (ISC_R_NOMORE);
1441         else
1442                 return (ISC_R_SUCCESS);
1443 }
1444
1445 static isc_result_t
1446 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1447         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1448
1449         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1450         while (sdbiter->current != NULL) {
1451                 if (dns_name_equal(sdbiter->current->name, name))
1452                         return (ISC_R_SUCCESS);
1453                 sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1454         }
1455         return (ISC_R_NOTFOUND);
1456 }
1457
1458 static isc_result_t
1459 dbiterator_prev(dns_dbiterator_t *iterator) {
1460         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1461
1462         sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1463         if (sdbiter->current == NULL)
1464                 return (ISC_R_NOMORE);
1465         else
1466                 return (ISC_R_SUCCESS);
1467 }
1468
1469 static isc_result_t
1470 dbiterator_next(dns_dbiterator_t *iterator) {
1471         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1472
1473         sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1474         if (sdbiter->current == NULL)
1475                 return (ISC_R_NOMORE);
1476         else
1477                 return (ISC_R_SUCCESS);
1478 }
1479
1480 static isc_result_t
1481 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1482                    dns_name_t *name)
1483 {
1484         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1485
1486         attachnode(iterator->db, sdbiter->current, nodep);
1487         if (name != NULL)
1488                 return (dns_name_copy(sdbiter->current->name, name, NULL));
1489         return (ISC_R_SUCCESS);
1490 }
1491
1492 static isc_result_t
1493 dbiterator_pause(dns_dbiterator_t *iterator) {
1494         UNUSED(iterator);
1495         return (ISC_R_SUCCESS);
1496 }
1497
1498 static isc_result_t
1499 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1500         UNUSED(iterator);
1501         return (dns_name_copy(dns_rootname, name, NULL));
1502 }
1503
1504 /*
1505  * Rdataset Iterator Methods
1506  */
1507
1508 static void
1509 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1510         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1511         detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1512         isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1513                     sizeof(sdb_rdatasetiter_t));
1514         *iteratorp = NULL;
1515 }
1516
1517 static isc_result_t
1518 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1519         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1520         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1521
1522         if (ISC_LIST_EMPTY(sdbnode->lists))
1523                 return (ISC_R_NOMORE);
1524         sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1525         return (ISC_R_SUCCESS);
1526 }
1527
1528 static isc_result_t
1529 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1530         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1531
1532         sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1533         if (sdbiterator->current == NULL)
1534                 return (ISC_R_NOMORE);
1535         else
1536                 return (ISC_R_SUCCESS);
1537 }
1538
1539 static void
1540 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1541         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1542
1543         list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1544                         rdataset);
1545 }