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