Merge from vendor branch BIND:
[dragonfly.git] / contrib / bind-9.3 / 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.12.8 2004/07/22 04:01:58 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(unsigned int len) {
271         unsigned int size;
272         for (size = 64; size < (64 * 1024); size *= 2)
273                 if (len < size)
274                         return (size);
275         return (64 * 1024);
276 }
277
278 isc_result_t
279 dns_sdb_putrdata(dns_sdblookup_t *lookup, dns_rdatatype_t typeval, dns_ttl_t ttl,
280                  const unsigned char *rdatap, unsigned int rdlen)
281 {
282         dns_rdatalist_t *rdatalist;
283         dns_rdata_t *rdata;
284         isc_buffer_t *rdatabuf = NULL;
285         isc_result_t result;
286         isc_mem_t *mctx;
287         isc_region_t region;
288
289         mctx = lookup->sdb->common.mctx;
290
291         rdatalist = ISC_LIST_HEAD(lookup->lists);
292         while (rdatalist != NULL) {
293                 if (rdatalist->type == typeval)
294                         break;
295                 rdatalist = ISC_LIST_NEXT(rdatalist, link);
296         }
297
298         if (rdatalist == NULL) {
299                 rdatalist = isc_mem_get(mctx, sizeof(dns_rdatalist_t));
300                 if (rdatalist == NULL)
301                         return (ISC_R_NOMEMORY);
302                 rdatalist->rdclass = lookup->sdb->common.rdclass;
303                 rdatalist->type = typeval;
304                 rdatalist->covers = 0;
305                 rdatalist->ttl = ttl;
306                 ISC_LIST_INIT(rdatalist->rdata);
307                 ISC_LINK_INIT(rdatalist, link);
308                 ISC_LIST_APPEND(lookup->lists, rdatalist, link);
309         } else 
310                 if (rdatalist->ttl != ttl)
311                         return (DNS_R_BADTTL);
312
313         rdata = isc_mem_get(mctx, sizeof(dns_rdata_t));
314         if (rdata == NULL)
315                 return (ISC_R_NOMEMORY);
316
317         result = isc_buffer_allocate(mctx, &rdatabuf, rdlen);
318         if (result != ISC_R_SUCCESS)
319                 goto failure;
320         DE_CONST(rdatap, region.base);
321         region.length = rdlen;
322         isc_buffer_copyregion(rdatabuf, &region);
323         isc_buffer_usedregion(rdatabuf, &region);
324         dns_rdata_init(rdata);
325         dns_rdata_fromregion(rdata, rdatalist->rdclass, rdatalist->type,
326                              &region);
327         ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
328         ISC_LIST_APPEND(lookup->buffers, rdatabuf, link);
329         rdata = NULL;
330
331  failure:
332         if (rdata != NULL)
333                 isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
334         return (result);
335 }
336         
337
338 isc_result_t
339 dns_sdb_putrr(dns_sdblookup_t *lookup, const char *type, dns_ttl_t ttl,
340               const char *data)
341 {
342         unsigned int datalen;
343         dns_rdatatype_t typeval;
344         isc_textregion_t r;
345         isc_lex_t *lex = NULL;
346         isc_result_t result;
347         unsigned char *p = NULL;
348         unsigned int size = 0; /* Init to suppress compiler warning */
349         isc_mem_t *mctx;
350         dns_sdbimplementation_t *imp;
351         dns_name_t *origin;
352         isc_buffer_t b;
353         isc_buffer_t rb;
354
355         REQUIRE(VALID_SDBLOOKUP(lookup));
356         REQUIRE(type != NULL);
357         REQUIRE(data != NULL);
358
359         mctx = lookup->sdb->common.mctx;
360
361         DE_CONST(type, r.base);
362         r.length = strlen(type);
363         result = dns_rdatatype_fromtext(&typeval, &r);
364         if (result != ISC_R_SUCCESS)
365                 return (result);
366
367         imp = lookup->sdb->implementation;
368         if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
369                 origin = &lookup->sdb->common.origin;
370         else
371                 origin = dns_rootname;
372
373         result = isc_lex_create(mctx, 64, &lex);
374         if (result != ISC_R_SUCCESS)
375                 goto failure;
376
377         datalen = strlen(data);
378         size = initial_size(datalen);
379         for (;;) {
380                 isc_buffer_init(&b, data, datalen);
381                 isc_buffer_add(&b, datalen);
382                 result = isc_lex_openbuffer(lex, &b);
383                 if (result != ISC_R_SUCCESS)
384                         goto failure;
385
386                 p = isc_mem_get(mctx, size);
387                 if (p == NULL) {
388                         result = ISC_R_NOMEMORY;
389                         goto failure;
390                 }
391                 isc_buffer_init(&rb, p, size);
392                 result = dns_rdata_fromtext(NULL,
393                                             lookup->sdb->common.rdclass,
394                                             typeval, lex,
395                                             origin, 0,
396                                             mctx, &rb,
397                                             &lookup->callbacks);
398                 if (result != ISC_R_NOSPACE)
399                         break;
400
401                 isc_mem_put(mctx, p, size);
402                 p = NULL;
403                 size *= 2;
404         } while (result == ISC_R_NOSPACE);
405
406         if (result != ISC_R_SUCCESS)
407                 goto failure;
408
409         result = dns_sdb_putrdata(lookup, typeval, ttl,
410                                   isc_buffer_base(&rb),
411                                   isc_buffer_usedlength(&rb));
412  failure:
413         if (p != NULL)
414                 isc_mem_put(mctx, p, size);
415         if (lex != NULL)
416                 isc_lex_destroy(&lex);
417
418         return (result);
419 }
420
421 static isc_result_t
422 getnode(dns_sdballnodes_t *allnodes, const char *name, dns_sdbnode_t **nodep) {
423         dns_name_t *newname, *origin;
424         dns_fixedname_t fnewname;
425         dns_sdb_t *sdb = (dns_sdb_t *)allnodes->common.db;
426         dns_sdbimplementation_t *imp = sdb->implementation;
427         dns_sdbnode_t *sdbnode;
428         isc_mem_t *mctx = sdb->common.mctx;
429         isc_buffer_t b;
430         isc_result_t result;
431
432         dns_fixedname_init(&fnewname);
433         newname = dns_fixedname_name(&fnewname);
434
435         if ((imp->flags & DNS_SDBFLAG_RELATIVERDATA) != 0)
436                 origin = &sdb->common.origin;
437         else
438                 origin = dns_rootname;
439         isc_buffer_init(&b, name, strlen(name));
440         isc_buffer_add(&b, strlen(name));
441
442         result = dns_name_fromtext(newname, &b, origin, ISC_FALSE, NULL);
443         if (result != ISC_R_SUCCESS)
444                 return (result);
445
446         if (allnodes->common.relative_names) {
447                 /* All names are relative to the root */
448                 unsigned int nlabels = dns_name_countlabels(newname);
449                 dns_name_getlabelsequence(newname, 0, nlabels - 1, newname);
450         }
451
452         sdbnode = ISC_LIST_HEAD(allnodes->nodelist);
453         if (sdbnode == NULL || !dns_name_equal(sdbnode->name, newname)) {
454                 sdbnode = NULL;
455                 result = createnode(sdb, &sdbnode);
456                 if (result != ISC_R_SUCCESS)
457                         return (result);
458                 sdbnode->name = isc_mem_get(mctx, sizeof(dns_name_t));
459                 if (sdbnode->name == NULL) {
460                         destroynode(sdbnode);
461                         return (ISC_R_NOMEMORY);
462                 }
463                 dns_name_init(sdbnode->name, NULL);
464                 result = dns_name_dup(newname, mctx, sdbnode->name);
465                 if (result != ISC_R_SUCCESS) {
466                         isc_mem_put(mctx, sdbnode->name, sizeof(dns_name_t));
467                         destroynode(sdbnode);
468                         return (result);
469                 }
470                 ISC_LIST_PREPEND(allnodes->nodelist, sdbnode, link);
471                 if (allnodes->origin == NULL &&
472                     dns_name_equal(newname, &sdb->common.origin))
473                         allnodes->origin = sdbnode;
474         }
475         *nodep = sdbnode;
476         return (ISC_R_SUCCESS);
477 }
478
479 isc_result_t
480 dns_sdb_putnamedrr(dns_sdballnodes_t *allnodes, const char *name,
481                    const char *type, dns_ttl_t ttl, const char *data)
482 {
483         isc_result_t result;
484         dns_sdbnode_t *sdbnode = NULL;
485         result = getnode(allnodes, name, &sdbnode);
486         if (result != ISC_R_SUCCESS)
487                 return (result);
488         return (dns_sdb_putrr(sdbnode, type, ttl, data));
489 }
490
491 isc_result_t
492 dns_sdb_putnamedrdata(dns_sdballnodes_t *allnodes, const char *name,
493                       dns_rdatatype_t type, dns_ttl_t ttl,
494                       const void *rdata, unsigned int rdlen)
495 {
496         isc_result_t result;
497         dns_sdbnode_t *sdbnode = NULL;
498         result = getnode(allnodes, name, &sdbnode);
499         if (result != ISC_R_SUCCESS)
500                 return (result);
501         return (dns_sdb_putrdata(sdbnode, type, ttl, rdata, rdlen));
502 }
503
504 isc_result_t
505 dns_sdb_putsoa(dns_sdblookup_t *lookup, const char *mname, const char *rname,
506                isc_uint32_t serial)
507 {
508         char str[2 * DNS_NAME_MAXTEXT + 5 * (sizeof("2147483647")) + 7];
509         int n;
510
511         REQUIRE(mname != NULL);
512         REQUIRE(rname != NULL);
513
514         n = snprintf(str, sizeof(str), "%s %s %u %u %u %u %u",
515                      mname, rname, serial,
516                      SDB_DEFAULT_REFRESH, SDB_DEFAULT_RETRY,
517                      SDB_DEFAULT_EXPIRE, SDB_DEFAULT_MINIMUM);
518         if (n >= (int)sizeof(str) || n < 0)
519                 return (ISC_R_NOSPACE);
520         return (dns_sdb_putrr(lookup, "SOA", SDB_DEFAULT_TTL, str));
521 }
522
523 /*
524  * DB routines
525  */
526
527 static void
528 attach(dns_db_t *source, dns_db_t **targetp) {
529         dns_sdb_t *sdb = (dns_sdb_t *) source;
530
531         REQUIRE(VALID_SDB(sdb));
532
533         LOCK(&sdb->lock);
534         REQUIRE(sdb->references > 0);
535         sdb->references++;
536         UNLOCK(&sdb->lock);
537
538         *targetp = source;
539 }
540
541 static void
542 destroy(dns_sdb_t *sdb) {
543         isc_mem_t *mctx;
544         dns_sdbimplementation_t *imp = sdb->implementation;
545
546         mctx = sdb->common.mctx;
547
548         if (imp->methods->destroy != NULL) {
549                 MAYBE_LOCK(sdb);
550                 imp->methods->destroy(sdb->zone, imp->driverdata,
551                                       &sdb->dbdata);
552                 MAYBE_UNLOCK(sdb);
553         }
554
555         isc_mem_free(mctx, sdb->zone);
556         DESTROYLOCK(&sdb->lock);
557
558         sdb->common.magic = 0;
559         sdb->common.impmagic = 0;
560
561         dns_name_free(&sdb->common.origin, mctx);
562
563         isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
564         isc_mem_detach(&mctx);
565 }
566
567 static void
568 detach(dns_db_t **dbp) {
569         dns_sdb_t *sdb = (dns_sdb_t *)(*dbp);
570         isc_boolean_t need_destroy = ISC_FALSE;
571
572         REQUIRE(VALID_SDB(sdb));
573         LOCK(&sdb->lock);
574         REQUIRE(sdb->references > 0);
575         sdb->references--;
576         if (sdb->references == 0)
577                 need_destroy = ISC_TRUE;
578         UNLOCK(&sdb->lock);
579
580         if (need_destroy)
581                 destroy(sdb);
582
583         *dbp = NULL;
584 }
585
586 static isc_result_t
587 beginload(dns_db_t *db, dns_addrdatasetfunc_t *addp, dns_dbload_t **dbloadp) {
588         UNUSED(db);
589         UNUSED(addp);
590         UNUSED(dbloadp);
591         return (ISC_R_NOTIMPLEMENTED);
592 }
593
594 static isc_result_t
595 endload(dns_db_t *db, dns_dbload_t **dbloadp) {
596         UNUSED(db);
597         UNUSED(dbloadp);
598         return (ISC_R_NOTIMPLEMENTED);
599 }
600
601 static isc_result_t
602 dump(dns_db_t *db, dns_dbversion_t *version, const char *filename) {
603         UNUSED(db);
604         UNUSED(version);
605         UNUSED(filename);
606         return (ISC_R_NOTIMPLEMENTED);
607 }
608
609 static void
610 currentversion(dns_db_t *db, dns_dbversion_t **versionp) {
611         REQUIRE(versionp != NULL && *versionp == NULL);
612
613         UNUSED(db);
614
615         *versionp = (void *) &dummy;
616         return;
617 }
618
619 static isc_result_t
620 newversion(dns_db_t *db, dns_dbversion_t **versionp) {
621         UNUSED(db);
622         UNUSED(versionp);
623
624         return (ISC_R_NOTIMPLEMENTED);
625 }
626
627 static void
628 attachversion(dns_db_t *db, dns_dbversion_t *source, 
629               dns_dbversion_t **targetp)
630 {
631         REQUIRE(source != NULL && source == (void *) &dummy);
632         REQUIRE(targetp != NULL && *targetp == NULL);
633
634         UNUSED(db);
635         *targetp = source;
636         return;
637 }
638
639 static void
640 closeversion(dns_db_t *db, dns_dbversion_t **versionp, isc_boolean_t commit) {
641         REQUIRE(versionp != NULL && *versionp == (void *) &dummy);
642         REQUIRE(commit == ISC_FALSE);
643
644         UNUSED(db);
645         UNUSED(commit);
646
647         *versionp = NULL;
648 }
649
650 static isc_result_t
651 createnode(dns_sdb_t *sdb, dns_sdbnode_t **nodep) {
652         dns_sdbnode_t *node;
653         isc_result_t result;
654
655         node = isc_mem_get(sdb->common.mctx, sizeof(dns_sdbnode_t));
656         if (node == NULL)
657                 return (ISC_R_NOMEMORY);
658
659         node->sdb = NULL;
660         attach((dns_db_t *)sdb, (dns_db_t **)&node->sdb);
661         ISC_LIST_INIT(node->lists);
662         ISC_LIST_INIT(node->buffers);
663         ISC_LINK_INIT(node, link);
664         node->name = NULL;
665         result = isc_mutex_init(&node->lock);
666         if (result != ISC_R_SUCCESS) {
667                 UNEXPECTED_ERROR(__FILE__, __LINE__,
668                                  "isc_mutex_init() failed: %s",
669                                  isc_result_totext(result));
670                 isc_mem_put(sdb->common.mctx, node, sizeof(dns_sdbnode_t));
671                 return (ISC_R_UNEXPECTED);
672         }
673         dns_rdatacallbacks_init(&node->callbacks);
674         node->references = 1;
675         node->magic = SDBLOOKUP_MAGIC;
676
677         *nodep = node;
678         return (ISC_R_SUCCESS);
679 }
680
681 static void
682 destroynode(dns_sdbnode_t *node) {
683         dns_rdatalist_t *list;
684         dns_rdata_t *rdata;
685         isc_buffer_t *b;
686         dns_sdb_t *sdb;
687         isc_mem_t *mctx;
688
689         sdb = node->sdb;
690         mctx = sdb->common.mctx;
691
692         while (!ISC_LIST_EMPTY(node->lists)) {
693                 list = ISC_LIST_HEAD(node->lists);
694                 while (!ISC_LIST_EMPTY(list->rdata)) {
695                         rdata = ISC_LIST_HEAD(list->rdata);
696                         ISC_LIST_UNLINK(list->rdata, rdata, link);
697                         isc_mem_put(mctx, rdata, sizeof(dns_rdata_t));
698                 }
699                 ISC_LIST_UNLINK(node->lists, list, link);
700                 isc_mem_put(mctx, list, sizeof(dns_rdatalist_t));
701         }
702
703         while (!ISC_LIST_EMPTY(node->buffers)) {
704                 b = ISC_LIST_HEAD(node->buffers);
705                 ISC_LIST_UNLINK(node->buffers, b, link);
706                 isc_buffer_free(&b);
707         }
708
709         if (node->name != NULL) {
710                 dns_name_free(node->name, mctx);
711                 isc_mem_put(mctx, node->name, sizeof(dns_name_t));
712         }
713         DESTROYLOCK(&node->lock);
714         node->magic = 0;
715         isc_mem_put(mctx, node, sizeof(dns_sdbnode_t));
716         detach((dns_db_t **) (void *)&sdb);
717 }
718
719 static isc_result_t
720 findnode(dns_db_t *db, dns_name_t *name, isc_boolean_t create,
721          dns_dbnode_t **nodep)
722 {
723         dns_sdb_t *sdb = (dns_sdb_t *)db;
724         dns_sdbnode_t *node = NULL;
725         isc_result_t result;
726         isc_buffer_t b;
727         char namestr[DNS_NAME_MAXTEXT + 1];
728         isc_boolean_t isorigin;
729         dns_sdbimplementation_t *imp;
730
731         REQUIRE(VALID_SDB(sdb));
732         REQUIRE(create == ISC_FALSE);
733         REQUIRE(nodep != NULL && *nodep == NULL);
734
735         UNUSED(name);
736         UNUSED(create);
737
738         imp = sdb->implementation;
739
740         isc_buffer_init(&b, namestr, sizeof(namestr));
741         if ((imp->flags & DNS_SDBFLAG_RELATIVEOWNER) != 0) {
742                 dns_name_t relname;
743                 unsigned int labels;
744
745                 labels = dns_name_countlabels(name) -
746                          dns_name_countlabels(&db->origin);
747                 dns_name_init(&relname, NULL);
748                 dns_name_getlabelsequence(name, 0, labels, &relname);
749                 result = dns_name_totext(&relname, ISC_TRUE, &b);
750                 if (result != ISC_R_SUCCESS)
751                         return (result);
752         } else {
753                 result = dns_name_totext(name, ISC_TRUE, &b);
754                 if (result != ISC_R_SUCCESS)
755                         return (result);
756         }
757         isc_buffer_putuint8(&b, 0);
758
759         result = createnode(sdb, &node);
760         if (result != ISC_R_SUCCESS)
761                 return (result);
762
763         isorigin = dns_name_equal(name, &sdb->common.origin);
764
765         MAYBE_LOCK(sdb);
766         result = imp->methods->lookup(sdb->zone, namestr, sdb->dbdata, node);
767         MAYBE_UNLOCK(sdb);
768         if (result != ISC_R_SUCCESS &&
769             !(result == ISC_R_NOTFOUND &&
770               isorigin && imp->methods->authority != NULL))
771         {
772                 destroynode(node);
773                 return (result);
774         }
775
776         if (isorigin && imp->methods->authority != NULL) {
777                 MAYBE_LOCK(sdb);
778                 result = imp->methods->authority(sdb->zone, sdb->dbdata, node);
779                 MAYBE_UNLOCK(sdb);
780                 if (result != ISC_R_SUCCESS) {
781                         destroynode(node);
782                         return (result);
783                 }
784         }
785         
786         *nodep = node;
787         return (ISC_R_SUCCESS);
788 }
789
790 static isc_result_t
791 find(dns_db_t *db, dns_name_t *name, dns_dbversion_t *version,
792      dns_rdatatype_t type, unsigned int options, isc_stdtime_t now,
793      dns_dbnode_t **nodep, dns_name_t *foundname,
794      dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
795 {
796         dns_sdb_t *sdb = (dns_sdb_t *)db;
797         dns_dbnode_t *node = NULL;
798         dns_fixedname_t fname;
799         dns_rdataset_t xrdataset;
800         dns_name_t *xname;
801         unsigned int nlabels, olabels;
802         isc_result_t result;
803         unsigned int i;
804
805         REQUIRE(VALID_SDB(sdb));
806         REQUIRE(nodep == NULL || *nodep == NULL);
807         REQUIRE(version == NULL || version == (void *) &dummy);
808
809         UNUSED(options);
810         UNUSED(sdb);
811
812         if (!dns_name_issubdomain(name, &db->origin))
813                 return (DNS_R_NXDOMAIN);
814
815         olabels = dns_name_countlabels(&db->origin);
816         nlabels = dns_name_countlabels(name);
817
818         dns_fixedname_init(&fname);
819         xname = dns_fixedname_name(&fname);
820
821         if (rdataset == NULL) {
822                 dns_rdataset_init(&xrdataset);
823                 rdataset = &xrdataset;
824         }
825
826         result = DNS_R_NXDOMAIN;
827
828         for (i = olabels; i <= nlabels; i++) {
829                 /*
830                  * Unless this is an explicit lookup at the origin, don't
831                  * look at the origin.
832                  */
833                 if (i == olabels && i != nlabels)
834                         continue;
835
836                 /*
837                  * Look up the next label.
838                  */
839                 dns_name_getlabelsequence(name, nlabels - i, i, xname);
840                 result = findnode(db, xname, ISC_FALSE, &node);
841                 if (result != ISC_R_SUCCESS) {
842                         result = DNS_R_NXDOMAIN;
843                         continue;
844                 }
845
846                 /*
847                  * Look for a DNAME at the current label, unless this is
848                  * the qname.
849                  */
850                 if (i < nlabels) {
851                         result = findrdataset(db, node, version,
852                                               dns_rdatatype_dname,
853                                               0, now, rdataset, sigrdataset);
854                         if (result == ISC_R_SUCCESS) {
855                                 result = DNS_R_DNAME;
856                                 break;
857                         }
858                 }
859
860                 /*
861                  * Look for an NS at the current label, unless this is the
862                  * origin or glue is ok.
863                  */
864                 if (i != olabels && (options & DNS_DBFIND_GLUEOK) == 0) {
865                         result = findrdataset(db, node, version,
866                                               dns_rdatatype_ns,
867                                               0, now, rdataset, sigrdataset);
868                         if (result == ISC_R_SUCCESS) {
869                                 if (i == nlabels && type == dns_rdatatype_any)
870                                 {
871                                         result = DNS_R_ZONECUT;
872                                         dns_rdataset_disassociate(rdataset);
873                                         if (sigrdataset != NULL)
874                                                 dns_rdataset_disassociate
875                                                                 (sigrdataset);
876                                 } else
877                                         result = DNS_R_DELEGATION;
878                                 break;
879                         }
880                 }
881
882                 /*
883                  * If the current name is not the qname, add another label
884                  * and try again.
885                  */
886                 if (i < nlabels) {
887                         destroynode(node);
888                         node = NULL;
889                         continue;
890                 }
891
892                 /*
893                  * If we're looking for ANY, we're done.
894                  */
895                 if (type == dns_rdatatype_any) {
896                         result = ISC_R_SUCCESS;
897                         break;
898                 }
899
900                 /*
901                  * Look for the qtype.
902                  */
903                 result = findrdataset(db, node, version, type,
904                                       0, now, rdataset, sigrdataset);
905                 if (result == ISC_R_SUCCESS)
906                         break;
907
908                 /*
909                  * Look for a CNAME
910                  */
911                 if (type != dns_rdatatype_cname) {
912                         result = findrdataset(db, node, version,
913                                               dns_rdatatype_cname,
914                                               0, now, rdataset, sigrdataset);
915                         if (result == ISC_R_SUCCESS) {
916                                 result = DNS_R_CNAME;
917                                 break;
918                         }
919                 }
920
921                 result = DNS_R_NXRRSET;
922                 break;
923         }
924
925         if (rdataset == &xrdataset && dns_rdataset_isassociated(rdataset))
926                 dns_rdataset_disassociate(rdataset);
927
928         if (foundname != NULL) {
929                 isc_result_t xresult;
930
931                 xresult = dns_name_copy(xname, foundname, NULL);
932                 if (xresult != ISC_R_SUCCESS) {
933                         destroynode(node);
934                         if (dns_rdataset_isassociated(rdataset))
935                                 dns_rdataset_disassociate(rdataset);
936                         return (DNS_R_BADDB);
937                 }
938         }
939
940         if (nodep != NULL)
941                 *nodep = node;
942         else if (node != NULL)
943                 detachnode(db, &node);
944
945         return (result);
946 }
947
948 static isc_result_t
949 findzonecut(dns_db_t *db, dns_name_t *name, unsigned int options,
950             isc_stdtime_t now, dns_dbnode_t **nodep, dns_name_t *foundname,
951             dns_rdataset_t *rdataset, dns_rdataset_t *sigrdataset)
952 {
953         UNUSED(db);
954         UNUSED(name);
955         UNUSED(options);
956         UNUSED(now);
957         UNUSED(nodep);
958         UNUSED(foundname);
959         UNUSED(rdataset);
960         UNUSED(sigrdataset);
961
962         return (ISC_R_NOTIMPLEMENTED);
963 }
964
965 static void
966 attachnode(dns_db_t *db, dns_dbnode_t *source, dns_dbnode_t **targetp) {
967         dns_sdb_t *sdb = (dns_sdb_t *)db;
968         dns_sdbnode_t *node = (dns_sdbnode_t *)source;
969
970         REQUIRE(VALID_SDB(sdb));
971
972         UNUSED(sdb);
973
974         LOCK(&node->lock);
975         INSIST(node->references > 0);
976         node->references++;
977         INSIST(node->references != 0);          /* Catch overflow. */
978         UNLOCK(&node->lock);
979
980         *targetp = source;
981 }
982
983 static void
984 detachnode(dns_db_t *db, dns_dbnode_t **targetp) {
985         dns_sdb_t *sdb = (dns_sdb_t *)db;
986         dns_sdbnode_t *node;
987         isc_boolean_t need_destroy = ISC_FALSE;
988
989         REQUIRE(VALID_SDB(sdb));
990         REQUIRE(targetp != NULL && *targetp != NULL);
991
992         UNUSED(sdb);
993
994         node = (dns_sdbnode_t *)(*targetp);
995
996         LOCK(&node->lock);
997         INSIST(node->references > 0);
998         node->references--;
999         if (node->references == 0)
1000                 need_destroy = ISC_TRUE;
1001         UNLOCK(&node->lock);
1002
1003         if (need_destroy)
1004                 destroynode(node);
1005
1006         *targetp = NULL;
1007 }
1008
1009 static isc_result_t
1010 expirenode(dns_db_t *db, dns_dbnode_t *node, isc_stdtime_t now) {
1011         UNUSED(db);
1012         UNUSED(node);
1013         UNUSED(now);
1014         INSIST(0);
1015         return (ISC_R_UNEXPECTED);
1016 }
1017
1018 static void
1019 printnode(dns_db_t *db, dns_dbnode_t *node, FILE *out) {
1020         UNUSED(db);
1021         UNUSED(node);
1022         UNUSED(out);
1023         return;
1024 }
1025
1026 static isc_result_t
1027 createiterator(dns_db_t *db, isc_boolean_t relative_names,
1028                dns_dbiterator_t **iteratorp)
1029 {
1030         dns_sdb_t *sdb = (dns_sdb_t *)db;
1031         sdb_dbiterator_t *sdbiter;
1032         dns_sdbimplementation_t *imp = sdb->implementation;
1033         isc_result_t result;
1034
1035         REQUIRE(VALID_SDB(sdb));
1036
1037         if (imp->methods->allnodes == NULL)
1038                 return (ISC_R_NOTIMPLEMENTED);
1039
1040         sdbiter = isc_mem_get(sdb->common.mctx, sizeof(sdb_dbiterator_t));
1041         if (sdbiter == NULL)
1042                 return (ISC_R_NOMEMORY);
1043
1044         sdbiter->common.methods = &dbiterator_methods;
1045         sdbiter->common.db = NULL;
1046         dns_db_attach(db, &sdbiter->common.db);
1047         sdbiter->common.relative_names = relative_names;
1048         sdbiter->common.magic = DNS_DBITERATOR_MAGIC;
1049         ISC_LIST_INIT(sdbiter->nodelist);
1050         sdbiter->current = NULL;
1051         sdbiter->origin = NULL;
1052
1053         MAYBE_LOCK(sdb);
1054         result = imp->methods->allnodes(sdb->zone, sdb->dbdata, sdbiter);
1055         MAYBE_UNLOCK(sdb);
1056         if (result != ISC_R_SUCCESS) {
1057                 dbiterator_destroy((dns_dbiterator_t **) (void *)&sdbiter);
1058                 return (result);
1059         }
1060
1061         if (sdbiter->origin != NULL) {
1062                 ISC_LIST_UNLINK(sdbiter->nodelist, sdbiter->origin, link);
1063                 ISC_LIST_PREPEND(sdbiter->nodelist, sdbiter->origin, link);
1064         }
1065
1066         *iteratorp = (dns_dbiterator_t *)sdbiter;
1067
1068         return (ISC_R_SUCCESS);
1069 }
1070
1071 static isc_result_t
1072 findrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1073              dns_rdatatype_t type, dns_rdatatype_t covers,
1074              isc_stdtime_t now, dns_rdataset_t *rdataset,
1075              dns_rdataset_t *sigrdataset)
1076 {
1077         dns_rdatalist_t *list;
1078         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)node;
1079
1080         REQUIRE(VALID_SDBNODE(node));
1081
1082         UNUSED(db);
1083         UNUSED(version);
1084         UNUSED(covers);
1085         UNUSED(now);
1086         UNUSED(sigrdataset);
1087
1088         if (type == dns_rdatatype_rrsig)
1089                 return (ISC_R_NOTIMPLEMENTED);
1090
1091         list = ISC_LIST_HEAD(sdbnode->lists);
1092         while (list != NULL) {
1093                 if (list->type == type)
1094                         break;
1095                 list = ISC_LIST_NEXT(list, link);
1096         }
1097         if (list == NULL)
1098                 return (ISC_R_NOTFOUND);
1099
1100         list_tordataset(list, db, node, rdataset);
1101
1102         return (ISC_R_SUCCESS);
1103 }
1104
1105 static isc_result_t
1106 allrdatasets(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1107              isc_stdtime_t now, dns_rdatasetiter_t **iteratorp)
1108 {
1109         sdb_rdatasetiter_t *iterator;
1110
1111         REQUIRE(version == NULL || version == &dummy);
1112         
1113         UNUSED(version);
1114         UNUSED(now);
1115
1116         iterator = isc_mem_get(db->mctx, sizeof(sdb_rdatasetiter_t));
1117         if (iterator == NULL)
1118                 return (ISC_R_NOMEMORY);
1119
1120         iterator->common.magic = DNS_RDATASETITER_MAGIC;
1121         iterator->common.methods = &rdatasetiter_methods;
1122         iterator->common.db = db;
1123         iterator->common.node = NULL;
1124         attachnode(db, node, &iterator->common.node);
1125         iterator->common.version = version;
1126         iterator->common.now = now;
1127
1128         *iteratorp = (dns_rdatasetiter_t *)iterator;
1129
1130         return (ISC_R_SUCCESS);
1131 }
1132
1133 static isc_result_t
1134 addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1135             isc_stdtime_t now, dns_rdataset_t *rdataset, unsigned int options,
1136             dns_rdataset_t *addedrdataset)
1137 {
1138         UNUSED(db);
1139         UNUSED(node);
1140         UNUSED(version);
1141         UNUSED(now);
1142         UNUSED(rdataset);
1143         UNUSED(options);
1144         UNUSED(addedrdataset);
1145
1146         return (ISC_R_NOTIMPLEMENTED);
1147 }
1148
1149 static isc_result_t
1150 subtractrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1151                  dns_rdataset_t *rdataset, unsigned int options,
1152                  dns_rdataset_t *newrdataset)
1153 {
1154         UNUSED(db);
1155         UNUSED(node);
1156         UNUSED(version);
1157         UNUSED(rdataset);
1158         UNUSED(options);
1159         UNUSED(newrdataset);
1160
1161         return (ISC_R_NOTIMPLEMENTED);
1162 }
1163
1164 static isc_result_t
1165 deleterdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
1166                dns_rdatatype_t type, dns_rdatatype_t covers)
1167 {
1168         UNUSED(db);
1169         UNUSED(node);
1170         UNUSED(version);
1171         UNUSED(type);
1172         UNUSED(covers);
1173
1174         return (ISC_R_NOTIMPLEMENTED);
1175 }
1176
1177 static isc_boolean_t
1178 issecure(dns_db_t *db) {
1179         UNUSED(db);
1180
1181         return (ISC_FALSE);
1182 }
1183
1184 static unsigned int
1185 nodecount(dns_db_t *db) {
1186         UNUSED(db);
1187
1188         return (0);
1189 }
1190
1191 static isc_boolean_t
1192 ispersistent(dns_db_t *db) {
1193         UNUSED(db);
1194         return (ISC_TRUE);
1195 }
1196
1197 static void
1198 overmem(dns_db_t *db, isc_boolean_t overmem) {
1199         UNUSED(db);
1200         UNUSED(overmem);
1201 }
1202
1203 static void
1204 settask(dns_db_t *db, isc_task_t *task) {
1205         UNUSED(db);
1206         UNUSED(task);
1207 }
1208
1209
1210 static dns_dbmethods_t sdb_methods = {
1211         attach,
1212         detach,
1213         beginload,
1214         endload,
1215         dump,
1216         currentversion,
1217         newversion,
1218         attachversion,
1219         closeversion,
1220         findnode,
1221         find,
1222         findzonecut,
1223         attachnode,
1224         detachnode,
1225         expirenode,
1226         printnode,
1227         createiterator,
1228         findrdataset,
1229         allrdatasets,
1230         addrdataset,
1231         subtractrdataset,
1232         deleterdataset,
1233         issecure,
1234         nodecount,
1235         ispersistent,
1236         overmem,
1237         settask
1238 };
1239
1240 static isc_result_t
1241 dns_sdb_create(isc_mem_t *mctx, dns_name_t *origin, dns_dbtype_t type,
1242                dns_rdataclass_t rdclass, unsigned int argc, char *argv[],
1243                void *driverarg, dns_db_t **dbp)
1244 {
1245         dns_sdb_t *sdb;
1246         isc_result_t result;
1247         char zonestr[DNS_NAME_MAXTEXT + 1];
1248         isc_buffer_t b;
1249         dns_sdbimplementation_t *imp;
1250
1251         REQUIRE(driverarg != NULL);
1252
1253         imp = driverarg;
1254
1255         if (type != dns_dbtype_zone)
1256                 return (ISC_R_NOTIMPLEMENTED);
1257
1258         sdb = isc_mem_get(mctx, sizeof(dns_sdb_t));
1259         if (sdb == NULL)
1260                 return (ISC_R_NOMEMORY);
1261         memset(sdb, 0, sizeof(dns_sdb_t));
1262
1263         dns_name_init(&sdb->common.origin, NULL);
1264         sdb->common.attributes = 0;
1265         sdb->common.methods = &sdb_methods;
1266         sdb->common.rdclass = rdclass;
1267         sdb->common.mctx = NULL;
1268         sdb->implementation = imp;
1269
1270         isc_mem_attach(mctx, &sdb->common.mctx);
1271
1272         result = isc_mutex_init(&sdb->lock);
1273         if (result != ISC_R_SUCCESS) {
1274                 UNEXPECTED_ERROR(__FILE__, __LINE__,
1275                                  "isc_mutex_init() failed: %s",
1276                                  isc_result_totext(result));
1277                 result = ISC_R_UNEXPECTED;
1278                 goto cleanup_mctx;
1279         }
1280
1281         result = dns_name_dupwithoffsets(origin, mctx, &sdb->common.origin);
1282         if (result != ISC_R_SUCCESS)
1283                 goto cleanup_lock;
1284
1285         isc_buffer_init(&b, zonestr, sizeof(zonestr));
1286         result = dns_name_totext(origin, ISC_TRUE, &b);
1287         if (result != ISC_R_SUCCESS)
1288                 goto cleanup_origin;
1289         isc_buffer_putuint8(&b, 0);
1290
1291         sdb->zone = isc_mem_strdup(mctx, zonestr);
1292         if (sdb->zone == NULL) {
1293                 result = ISC_R_NOMEMORY;
1294                 goto cleanup_origin;
1295         }
1296
1297         sdb->dbdata = NULL;
1298         if (imp->methods->create != NULL) {
1299                 MAYBE_LOCK(sdb);
1300                 result = imp->methods->create(sdb->zone, argc, argv,
1301                                               imp->driverdata, &sdb->dbdata);
1302                 MAYBE_UNLOCK(sdb);
1303                 if (result != ISC_R_SUCCESS)
1304                         goto cleanup_zonestr;
1305         }
1306
1307         sdb->references = 1;
1308
1309         sdb->common.magic = DNS_DB_MAGIC;
1310         sdb->common.impmagic = SDB_MAGIC;
1311
1312         *dbp = (dns_db_t *)sdb;
1313
1314         return (ISC_R_SUCCESS);
1315
1316  cleanup_zonestr:
1317         isc_mem_free(mctx, sdb->zone);
1318  cleanup_origin:
1319         dns_name_free(&sdb->common.origin, mctx);
1320  cleanup_lock:
1321         isc_mutex_destroy(&sdb->lock);
1322  cleanup_mctx:
1323         isc_mem_put(mctx, sdb, sizeof(dns_sdb_t));
1324         isc_mem_detach(&mctx);
1325
1326         return (result);
1327 }
1328
1329
1330 /*
1331  * Rdataset Methods
1332  */
1333
1334 static void
1335 disassociate(dns_rdataset_t *rdataset) {
1336         dns_dbnode_t *node = rdataset->private5;
1337         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1338         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1339
1340         detachnode(db, &node);
1341         isc__rdatalist_disassociate(rdataset);
1342 }
1343
1344 static void
1345 rdataset_clone(dns_rdataset_t *source, dns_rdataset_t *target) {
1346         dns_dbnode_t *node = source->private5;
1347         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *) node;
1348         dns_db_t *db = (dns_db_t *) sdbnode->sdb;
1349         dns_dbnode_t *tempdb = NULL;
1350
1351         isc__rdatalist_clone(source, target);
1352         attachnode(db, node, &tempdb);
1353         source->private5 = tempdb;
1354 }
1355
1356 static dns_rdatasetmethods_t methods = {
1357         disassociate,
1358         isc__rdatalist_first,
1359         isc__rdatalist_next,
1360         isc__rdatalist_current,
1361         rdataset_clone,
1362         isc__rdatalist_count,
1363         isc__rdatalist_addnoqname,
1364         isc__rdatalist_getnoqname
1365 };
1366
1367 static void
1368 list_tordataset(dns_rdatalist_t *rdatalist,
1369                 dns_db_t *db, dns_dbnode_t *node,
1370                 dns_rdataset_t *rdataset)
1371 {
1372         /*
1373          * The sdb rdataset is an rdatalist with some additions.
1374          *      - private1 & private2 are used by the rdatalist.
1375          *      - private3 & private 4 are unused.
1376          *      - private5 is the node.
1377          */
1378
1379         /* This should never fail. */
1380         RUNTIME_CHECK(dns_rdatalist_tordataset(rdatalist, rdataset) ==
1381                       ISC_R_SUCCESS);
1382
1383         rdataset->methods = &methods;
1384         dns_db_attachnode(db, node, &rdataset->private5);
1385 }
1386
1387 /*
1388  * Database Iterator Methods
1389  */
1390 static void
1391 dbiterator_destroy(dns_dbiterator_t **iteratorp) {
1392         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)(*iteratorp);
1393         dns_sdb_t *sdb = (dns_sdb_t *)sdbiter->common.db;
1394
1395         while (!ISC_LIST_EMPTY(sdbiter->nodelist)) {
1396                 dns_sdbnode_t *node;
1397                 node = ISC_LIST_HEAD(sdbiter->nodelist);
1398                 ISC_LIST_UNLINK(sdbiter->nodelist, node, link);
1399                 destroynode(node);
1400         }
1401
1402         dns_db_detach(&sdbiter->common.db);
1403         isc_mem_put(sdb->common.mctx, sdbiter, sizeof(sdb_dbiterator_t));
1404
1405         *iteratorp = NULL;
1406 }
1407
1408 static isc_result_t
1409 dbiterator_first(dns_dbiterator_t *iterator) {
1410         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1411
1412         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1413         if (sdbiter->current == NULL)
1414                 return (ISC_R_NOMORE);
1415         else
1416                 return (ISC_R_SUCCESS);
1417 }
1418
1419 static isc_result_t
1420 dbiterator_last(dns_dbiterator_t *iterator) {
1421         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1422
1423         sdbiter->current = ISC_LIST_TAIL(sdbiter->nodelist);
1424         if (sdbiter->current == NULL)
1425                 return (ISC_R_NOMORE);
1426         else
1427                 return (ISC_R_SUCCESS);
1428 }
1429
1430 static isc_result_t
1431 dbiterator_seek(dns_dbiterator_t *iterator, dns_name_t *name) {
1432         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1433
1434         sdbiter->current = ISC_LIST_HEAD(sdbiter->nodelist);
1435         while (sdbiter->current != NULL)
1436                 if (dns_name_equal(sdbiter->current->name, name))
1437                         return (ISC_R_SUCCESS);
1438         return (ISC_R_NOTFOUND);
1439 }
1440
1441 static isc_result_t
1442 dbiterator_prev(dns_dbiterator_t *iterator) {
1443         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1444
1445         sdbiter->current = ISC_LIST_PREV(sdbiter->current, link);
1446         if (sdbiter->current == NULL)
1447                 return (ISC_R_NOMORE);
1448         else
1449                 return (ISC_R_SUCCESS);
1450 }
1451
1452 static isc_result_t
1453 dbiterator_next(dns_dbiterator_t *iterator) {
1454         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1455
1456         sdbiter->current = ISC_LIST_NEXT(sdbiter->current, link);
1457         if (sdbiter->current == NULL)
1458                 return (ISC_R_NOMORE);
1459         else
1460                 return (ISC_R_SUCCESS);
1461 }
1462
1463 static isc_result_t
1464 dbiterator_current(dns_dbiterator_t *iterator, dns_dbnode_t **nodep,
1465                    dns_name_t *name)
1466 {
1467         sdb_dbiterator_t *sdbiter = (sdb_dbiterator_t *)iterator;
1468
1469         attachnode(iterator->db, sdbiter->current, nodep);
1470         if (name != NULL)
1471                 return (dns_name_copy(sdbiter->current->name, name, NULL));
1472         return (ISC_R_SUCCESS);
1473 }
1474
1475 static isc_result_t
1476 dbiterator_pause(dns_dbiterator_t *iterator) {
1477         UNUSED(iterator);
1478         return (ISC_R_SUCCESS);
1479 }
1480
1481 static isc_result_t
1482 dbiterator_origin(dns_dbiterator_t *iterator, dns_name_t *name) {
1483         UNUSED(iterator);
1484         return (dns_name_copy(dns_rootname, name, NULL));
1485 }
1486
1487 /*
1488  * Rdataset Iterator Methods
1489  */
1490
1491 static void
1492 rdatasetiter_destroy(dns_rdatasetiter_t **iteratorp) {
1493         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)(*iteratorp);
1494         detachnode(sdbiterator->common.db, &sdbiterator->common.node);
1495         isc_mem_put(sdbiterator->common.db->mctx, sdbiterator,
1496                     sizeof(sdb_rdatasetiter_t));
1497         *iteratorp = NULL;
1498 }
1499
1500 static isc_result_t
1501 rdatasetiter_first(dns_rdatasetiter_t *iterator) {
1502         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1503         dns_sdbnode_t *sdbnode = (dns_sdbnode_t *)iterator->node;
1504
1505         if (ISC_LIST_EMPTY(sdbnode->lists))
1506                 return (ISC_R_NOMORE);
1507         sdbiterator->current = ISC_LIST_HEAD(sdbnode->lists);
1508         return (ISC_R_SUCCESS);
1509 }
1510
1511 static isc_result_t
1512 rdatasetiter_next(dns_rdatasetiter_t *iterator) {
1513         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1514
1515         sdbiterator->current = ISC_LIST_NEXT(sdbiterator->current, link);
1516         if (sdbiterator->current == NULL)
1517                 return (ISC_R_NOMORE);
1518         else
1519                 return (ISC_R_SUCCESS);
1520 }
1521
1522 static void
1523 rdatasetiter_current(dns_rdatasetiter_t *iterator, dns_rdataset_t *rdataset) {
1524         sdb_rdatasetiter_t *sdbiterator = (sdb_rdatasetiter_t *)iterator;
1525
1526         list_tordataset(sdbiterator->current, iterator->db, iterator->node,
1527                         rdataset);
1528 }