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