xref: /minix/external/bsd/bind/dist/lib/dns/masterdump.c (revision fb9c64b2)
1 /*	$NetBSD: masterdump.c,v 1.11 2015/07/08 17:28:58 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2004-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
5  * Copyright (C) 1999-2003  Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and/or distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17  * PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 /* Id */
21 
22 /*! \file */
23 
24 #include <config.h>
25 
26 #include <stdlib.h>
27 
28 #include <isc/event.h>
29 #include <isc/file.h>
30 #include <isc/magic.h>
31 #include <isc/mem.h>
32 #include <isc/print.h>
33 #include <isc/stdio.h>
34 #include <isc/string.h>
35 #include <isc/task.h>
36 #include <isc/time.h>
37 #include <isc/util.h>
38 
39 #include <dns/db.h>
40 #include <dns/dbiterator.h>
41 #include <dns/events.h>
42 #include <dns/fixedname.h>
43 #include <dns/lib.h>
44 #include <dns/log.h>
45 #include <dns/master.h>
46 #include <dns/masterdump.h>
47 #include <dns/ncache.h>
48 #include <dns/rdata.h>
49 #include <dns/rdataclass.h>
50 #include <dns/rdataset.h>
51 #include <dns/rdatasetiter.h>
52 #include <dns/rdatatype.h>
53 #include <dns/result.h>
54 #include <dns/time.h>
55 #include <dns/ttl.h>
56 
57 #define DNS_DCTX_MAGIC		ISC_MAGIC('D', 'c', 't', 'x')
58 #define DNS_DCTX_VALID(d)	ISC_MAGIC_VALID(d, DNS_DCTX_MAGIC)
59 
60 #define RETERR(x) do { \
61 	isc_result_t _r = (x); \
62 	if (_r != ISC_R_SUCCESS) \
63 		return (_r); \
64 	} while (/*CONSTCOND*/0)
65 
66 #define CHECK(x) do { \
67 	if ((x) != ISC_R_SUCCESS) \
68 		goto cleanup; \
69 	} while (/*CONSTCOND*/0)
70 
71 struct dns_master_style {
72 	unsigned int flags;		/* DNS_STYLEFLAG_* */
73 	unsigned int ttl_column;
74 	unsigned int class_column;
75 	unsigned int type_column;
76 	unsigned int rdata_column;
77 	unsigned int line_length;
78 	unsigned int tab_width;
79 	unsigned int split_width;
80 };
81 
82 /*%
83  * The maximum length of the newline+indentation that is output
84  * when inserting a line break in an RR.  This effectively puts an
85  * upper limits on the value of "rdata_column", because if it is
86  * very large, the tabs and spaces needed to reach it will not fit.
87  */
88 #define DNS_TOTEXT_LINEBREAK_MAXLEN 100
89 
90 /*%
91  * Context structure for a masterfile dump in progress.
92  */
93 typedef struct dns_totext_ctx {
94 	dns_master_style_t	style;
95 	isc_boolean_t 		class_printed;
96 	char *			linebreak;
97 	char 			linebreak_buf[DNS_TOTEXT_LINEBREAK_MAXLEN];
98 	dns_name_t *		origin;
99 	dns_name_t *		neworigin;
100 	dns_fixedname_t		origin_fixname;
101 	isc_uint32_t 		current_ttl;
102 	isc_boolean_t 		current_ttl_valid;
103 } dns_totext_ctx_t;
104 
105 LIBDNS_EXTERNAL_DATA const dns_master_style_t
106 dns_master_style_keyzone = {
107 	DNS_STYLEFLAG_OMIT_OWNER |
108 	DNS_STYLEFLAG_OMIT_CLASS |
109 	DNS_STYLEFLAG_REL_OWNER |
110 	DNS_STYLEFLAG_REL_DATA |
111 	DNS_STYLEFLAG_OMIT_TTL |
112 	DNS_STYLEFLAG_TTL |
113 	DNS_STYLEFLAG_COMMENT |
114 	DNS_STYLEFLAG_RRCOMMENT |
115 	DNS_STYLEFLAG_MULTILINE |
116 	DNS_STYLEFLAG_KEYDATA,
117 	24, 24, 24, 32, 80, 8, UINT_MAX
118 };
119 
120 LIBDNS_EXTERNAL_DATA const dns_master_style_t
121 dns_master_style_default = {
122 	DNS_STYLEFLAG_OMIT_OWNER |
123 	DNS_STYLEFLAG_OMIT_CLASS |
124 	DNS_STYLEFLAG_REL_OWNER |
125 	DNS_STYLEFLAG_REL_DATA |
126 	DNS_STYLEFLAG_OMIT_TTL |
127 	DNS_STYLEFLAG_TTL |
128 	DNS_STYLEFLAG_COMMENT |
129 	DNS_STYLEFLAG_RRCOMMENT |
130 	DNS_STYLEFLAG_MULTILINE,
131 	24, 24, 24, 32, 80, 8, UINT_MAX
132 };
133 
134 LIBDNS_EXTERNAL_DATA const dns_master_style_t
135 dns_master_style_full = {
136 	DNS_STYLEFLAG_COMMENT |
137 	DNS_STYLEFLAG_RESIGN,
138 	46, 46, 46, 64, 120, 8, UINT_MAX
139 };
140 
141 LIBDNS_EXTERNAL_DATA const dns_master_style_t
142 dns_master_style_explicitttl = {
143 	DNS_STYLEFLAG_OMIT_OWNER |
144 	DNS_STYLEFLAG_OMIT_CLASS |
145 	DNS_STYLEFLAG_REL_OWNER |
146 	DNS_STYLEFLAG_REL_DATA |
147 	DNS_STYLEFLAG_COMMENT |
148 	DNS_STYLEFLAG_RRCOMMENT |
149 	DNS_STYLEFLAG_MULTILINE,
150 	24, 32, 32, 40, 80, 8, UINT_MAX
151 };
152 
153 LIBDNS_EXTERNAL_DATA const dns_master_style_t
154 dns_master_style_cache = {
155 	DNS_STYLEFLAG_OMIT_OWNER |
156 	DNS_STYLEFLAG_OMIT_CLASS |
157 	DNS_STYLEFLAG_MULTILINE |
158 	DNS_STYLEFLAG_RRCOMMENT |
159 	DNS_STYLEFLAG_TRUST |
160 	DNS_STYLEFLAG_NCACHE,
161 	24, 32, 32, 40, 80, 8, UINT_MAX
162 };
163 
164 LIBDNS_EXTERNAL_DATA const dns_master_style_t
165 dns_master_style_simple = {
166 	0,
167 	24, 32, 32, 40, 80, 8, UINT_MAX
168 };
169 
170 /*%
171  * A style suitable for dns_rdataset_totext().
172  */
173 LIBDNS_EXTERNAL_DATA const dns_master_style_t
174 dns_master_style_debug = {
175 	DNS_STYLEFLAG_REL_OWNER,
176 	24, 32, 40, 48, 80, 8, UINT_MAX
177 };
178 
179 /*%
180  * Similar, but with each line commented out.
181  */
182 LIBDNS_EXTERNAL_DATA const dns_master_style_t
183 dns_master_style_comment = {
184 	DNS_STYLEFLAG_REL_OWNER |
185 	DNS_STYLEFLAG_MULTILINE |
186 	DNS_STYLEFLAG_RRCOMMENT |
187 	DNS_STYLEFLAG_COMMENTDATA,
188 	24, 32, 40, 48, 80, 8, UINT_MAX
189 };
190 
191 
192 #define N_SPACES 10
193 static char spaces[N_SPACES+1] = "          ";
194 
195 #define N_TABS 10
196 static char tabs[N_TABS+1] = "\t\t\t\t\t\t\t\t\t\t";
197 
198 struct dns_dumpctx {
199 	unsigned int		magic;
200 	isc_mem_t		*mctx;
201 	isc_mutex_t		lock;
202 	unsigned int		references;
203 	isc_boolean_t		canceled;
204 	isc_boolean_t		first;
205 	isc_boolean_t		do_date;
206 	isc_stdtime_t		now;
207 	FILE			*f;
208 	dns_db_t		*db;
209 	dns_dbversion_t		*version;
210 	dns_dbiterator_t	*dbiter;
211 	dns_totext_ctx_t	tctx;
212 	isc_task_t		*task;
213 	dns_dumpdonefunc_t	done;
214 	void			*done_arg;
215 	unsigned int		nodes;
216 	/* dns_master_dumpinc() */
217 	char			*file;
218 	char 			*tmpfile;
219 	dns_masterformat_t	format;
220 	dns_masterrawheader_t	header;
221 	isc_result_t		(*dumpsets)(isc_mem_t *mctx, dns_name_t *name,
222 					    dns_rdatasetiter_t *rdsiter,
223 					    dns_totext_ctx_t *ctx,
224 					    isc_buffer_t *buffer, FILE *f);
225 };
226 
227 #define NXDOMAIN(x) (((x)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0)
228 
229 /*%
230  * Output tabs and spaces to go from column '*current' to
231  * column 'to', and update '*current' to reflect the new
232  * current column.
233  */
234 static isc_result_t
235 indent(unsigned int *current, unsigned int to, int tabwidth,
236        isc_buffer_t *target)
237 {
238 	isc_region_t r;
239 	unsigned char *p;
240 	unsigned int from;
241 	int ntabs, nspaces, t;
242 
243 	from = *current;
244 
245 	if (to < from + 1)
246 		to = from + 1;
247 
248 	ntabs = to / tabwidth - from / tabwidth;
249 	if (ntabs < 0)
250 		ntabs = 0;
251 
252 	if (ntabs > 0) {
253 		isc_buffer_availableregion(target, &r);
254 		if (r.length < (unsigned) ntabs)
255 			return (ISC_R_NOSPACE);
256 		p = r.base;
257 
258 		t = ntabs;
259 		while (t) {
260 			int n = t;
261 			if (n > N_TABS)
262 				n = N_TABS;
263 			memmove(p, tabs, n);
264 			p += n;
265 			t -= n;
266 		}
267 		isc_buffer_add(target, ntabs);
268 		from = (to / tabwidth) * tabwidth;
269 	}
270 
271 	nspaces = to - from;
272 	INSIST(nspaces >= 0);
273 
274 	isc_buffer_availableregion(target, &r);
275 	if (r.length < (unsigned) nspaces)
276 		return (ISC_R_NOSPACE);
277 	p = r.base;
278 
279 	t = nspaces;
280 	while (t) {
281 		int n = t;
282 		if (n > N_SPACES)
283 			n = N_SPACES;
284 		memmove(p, spaces, n);
285 		p += n;
286 		t -= n;
287 	}
288 	isc_buffer_add(target, nspaces);
289 
290 	*current = to;
291 	return (ISC_R_SUCCESS);
292 }
293 
294 static isc_result_t
295 totext_ctx_init(const dns_master_style_t *style, dns_totext_ctx_t *ctx) {
296 	isc_result_t result;
297 
298 	REQUIRE(style->tab_width != 0);
299 
300 	ctx->style = *style;
301 	ctx->class_printed = ISC_FALSE;
302 
303 	dns_fixedname_init(&ctx->origin_fixname);
304 
305 	/*
306 	 * Set up the line break string if needed.
307 	 */
308 	if ((ctx->style.flags & DNS_STYLEFLAG_MULTILINE) != 0) {
309 		isc_buffer_t buf;
310 		isc_region_t r;
311 		unsigned int col = 0;
312 
313 		isc_buffer_init(&buf, ctx->linebreak_buf,
314 				sizeof(ctx->linebreak_buf));
315 
316 		isc_buffer_availableregion(&buf, &r);
317 		if (r.length < 1)
318 			return (DNS_R_TEXTTOOLONG);
319 		r.base[0] = '\n';
320 		isc_buffer_add(&buf, 1);
321 
322 		if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0) {
323 			isc_buffer_availableregion(&buf, &r);
324 			if (r.length < 1)
325 				return (DNS_R_TEXTTOOLONG);
326 			r.base[0] = ';';
327 			isc_buffer_add(&buf, 1);
328 		}
329 
330 		result = indent(&col, ctx->style.rdata_column,
331 				ctx->style.tab_width, &buf);
332 		/*
333 		 * Do not return ISC_R_NOSPACE if the line break string
334 		 * buffer is too small, because that would just make
335 		 * dump_rdataset() retry indefinitely with ever
336 		 * bigger target buffers.  That's a different buffer,
337 		 * so it won't help.  Use DNS_R_TEXTTOOLONG as a substitute.
338 		 */
339 		if (result == ISC_R_NOSPACE)
340 			return (DNS_R_TEXTTOOLONG);
341 		if (result != ISC_R_SUCCESS)
342 			return (result);
343 
344 		isc_buffer_availableregion(&buf, &r);
345 		if (r.length < 1)
346 			return (DNS_R_TEXTTOOLONG);
347 		r.base[0] = '\0';
348 		isc_buffer_add(&buf, 1);
349 		ctx->linebreak = ctx->linebreak_buf;
350 	} else {
351 		ctx->linebreak = NULL;
352 	}
353 
354 	ctx->origin = NULL;
355 	ctx->neworigin = NULL;
356 	ctx->current_ttl = 0;
357 	ctx->current_ttl_valid = ISC_FALSE;
358 
359 	return (ISC_R_SUCCESS);
360 }
361 
362 #define INDENT_TO(col) \
363 	do { \
364 		 if ((result = indent(&column, ctx->style.col, \
365 				      ctx->style.tab_width, target)) \
366 		     != ISC_R_SUCCESS) \
367 			    return (result); \
368 	} while (/*CONSTCOND*/0)
369 
370 
371 static isc_result_t
372 str_totext(const char *source, isc_buffer_t *target) {
373 	unsigned int l;
374 	isc_region_t region;
375 
376 	isc_buffer_availableregion(target, &region);
377 	l = strlen(source);
378 
379 	if (l > region.length)
380 		return (ISC_R_NOSPACE);
381 
382 	memmove(region.base, source, l);
383 	isc_buffer_add(target, l);
384 	return (ISC_R_SUCCESS);
385 }
386 
387 static isc_result_t
388 ncache_summary(dns_rdataset_t *rdataset, isc_boolean_t omit_final_dot,
389 	       isc_buffer_t *target)
390 {
391 	isc_result_t result = ISC_R_SUCCESS;
392 	dns_rdataset_t rds;
393 	dns_name_t name;
394 
395 	dns_rdataset_init(&rds);
396 	dns_name_init(&name, NULL);
397 
398 	do {
399 		dns_ncache_current(rdataset, &name, &rds);
400 		for (result = dns_rdataset_first(&rds);
401 		     result == ISC_R_SUCCESS;
402 		     result = dns_rdataset_next(&rds)) {
403 			CHECK(str_totext("; ", target));
404 			CHECK(dns_name_totext(&name, omit_final_dot, target));
405 			CHECK(str_totext(" ", target));
406 			CHECK(dns_rdatatype_totext(rds.type, target));
407 			if (rds.type == dns_rdatatype_rrsig) {
408 				CHECK(str_totext(" ", target));
409 				CHECK(dns_rdatatype_totext(rds.covers, target));
410 				CHECK(str_totext(" ...\n", target));
411 			} else {
412 				dns_rdata_t rdata = DNS_RDATA_INIT;
413 				dns_rdataset_current(&rds, &rdata);
414 				CHECK(str_totext(" ", target));
415 				CHECK(dns_rdata_tofmttext(&rdata, dns_rootname,
416 							  0, 0, 0, " ", target));
417 				CHECK(str_totext("\n", target));
418 			}
419 		}
420 		dns_rdataset_disassociate(&rds);
421 		result = dns_rdataset_next(rdataset);
422 	} while (result == ISC_R_SUCCESS);
423 
424 	if (result == ISC_R_NOMORE)
425 		result = ISC_R_SUCCESS;
426  cleanup:
427 	if (dns_rdataset_isassociated(&rds))
428 		dns_rdataset_disassociate(&rds);
429 
430 	return (result);
431 }
432 
433 /*
434  * Convert 'rdataset' to master file text format according to 'ctx',
435  * storing the result in 'target'.  If 'owner_name' is NULL, it
436  * is omitted; otherwise 'owner_name' must be valid and have at least
437  * one label.
438  */
439 
440 static isc_result_t
441 rdataset_totext(dns_rdataset_t *rdataset,
442 		dns_name_t *owner_name,
443 		dns_totext_ctx_t *ctx,
444 		isc_boolean_t omit_final_dot,
445 		isc_buffer_t *target)
446 {
447 	isc_result_t result;
448 	unsigned int column;
449 	isc_boolean_t first = ISC_TRUE;
450 	isc_uint32_t current_ttl;
451 	isc_boolean_t current_ttl_valid;
452 	dns_rdatatype_t type;
453 	unsigned int type_start;
454 
455 	REQUIRE(DNS_RDATASET_VALID(rdataset));
456 
457 	rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
458 	result = dns_rdataset_first(rdataset);
459 
460 	current_ttl = ctx->current_ttl;
461 	current_ttl_valid = ctx->current_ttl_valid;
462 
463 	while (result == ISC_R_SUCCESS) {
464 		column = 0;
465 
466 		/*
467 		 * Comment?
468 		 */
469 		if ((ctx->style.flags & DNS_STYLEFLAG_COMMENTDATA) != 0)
470 			RETERR(str_totext(";", target));
471 
472 		/*
473 		 * Owner name.
474 		 */
475 		if (owner_name != NULL &&
476 		    ! ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0 &&
477 		       !first))
478 		{
479 			unsigned int name_start = target->used;
480 			RETERR(dns_name_totext(owner_name,
481 					       omit_final_dot,
482 					       target));
483 			column += target->used - name_start;
484 		}
485 
486 		/*
487 		 * TTL.
488 		 */
489 		if ((ctx->style.flags & DNS_STYLEFLAG_NO_TTL) == 0 &&
490 		    !((ctx->style.flags & DNS_STYLEFLAG_OMIT_TTL) != 0 &&
491 		      current_ttl_valid &&
492 		      rdataset->ttl == current_ttl))
493 		{
494 			char ttlbuf[64];
495 			isc_region_t r;
496 			unsigned int length;
497 
498 			INDENT_TO(ttl_column);
499 			length = snprintf(ttlbuf, sizeof(ttlbuf), "%u",
500 					  rdataset->ttl);
501 			INSIST(length <= sizeof(ttlbuf));
502 			isc_buffer_availableregion(target, &r);
503 			if (r.length < length)
504 				return (ISC_R_NOSPACE);
505 			memmove(r.base, ttlbuf, length);
506 			isc_buffer_add(target, length);
507 			column += length;
508 
509 			/*
510 			 * If the $TTL directive is not in use, the TTL we
511 			 * just printed becomes the default for subsequent RRs.
512 			 */
513 			if ((ctx->style.flags & DNS_STYLEFLAG_TTL) == 0) {
514 				current_ttl = rdataset->ttl;
515 				current_ttl_valid = ISC_TRUE;
516 			}
517 		}
518 
519 		/*
520 		 * Class.
521 		 */
522 		if ((ctx->style.flags & DNS_STYLEFLAG_NO_CLASS) == 0 &&
523 		    ((ctx->style.flags & DNS_STYLEFLAG_OMIT_CLASS) == 0 ||
524 		     ctx->class_printed == ISC_FALSE))
525 		{
526 			unsigned int class_start;
527 			INDENT_TO(class_column);
528 			class_start = target->used;
529 			result = dns_rdataclass_totext(rdataset->rdclass,
530 						       target);
531 			if (result != ISC_R_SUCCESS)
532 				return (result);
533 			column += (target->used - class_start);
534 		}
535 
536 		/*
537 		 * Type.
538 		 */
539 
540 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
541 			type = rdataset->covers;
542 		} else {
543 			type = rdataset->type;
544 		}
545 
546 		INDENT_TO(type_column);
547 		type_start = target->used;
548 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0)
549 			RETERR(str_totext("\\-", target));
550 		switch (type) {
551 		case dns_rdatatype_keydata:
552 #define KEYDATA "KEYDATA"
553 			if ((ctx->style.flags & DNS_STYLEFLAG_KEYDATA) != 0) {
554 				if (isc_buffer_availablelength(target) <
555 				    (sizeof(KEYDATA) - 1))
556 					return (ISC_R_NOSPACE);
557 				isc_buffer_putstr(target, KEYDATA);
558 				break;
559 			}
560 			/* FALLTHROUGH */
561 		default:
562 			result = dns_rdatatype_totext(type, target);
563 			if (result != ISC_R_SUCCESS)
564 				return (result);
565 		}
566 		column += (target->used - type_start);
567 
568 		/*
569 		 * Rdata.
570 		 */
571 		INDENT_TO(rdata_column);
572 		if ((rdataset->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) {
573 			if (NXDOMAIN(rdataset))
574 				RETERR(str_totext(";-$NXDOMAIN\n", target));
575 			else
576 				RETERR(str_totext(";-$NXRRSET\n", target));
577 			/*
578 			 * Print a summary of the cached records which make
579 			 * up the negative response.
580 			 */
581 			RETERR(ncache_summary(rdataset, omit_final_dot,
582 					      target));
583 			break;
584 		} else {
585 			dns_rdata_t rdata = DNS_RDATA_INIT;
586 			isc_region_t r;
587 
588 			dns_rdataset_current(rdataset, &rdata);
589 
590 			RETERR(dns_rdata_tofmttext(&rdata,
591 						   ctx->origin,
592 						   ctx->style.flags,
593 						   ctx->style.line_length -
594 						       ctx->style.rdata_column,
595 						   ctx->style.split_width,
596 						   ctx->linebreak,
597 						   target));
598 
599 			isc_buffer_availableregion(target, &r);
600 			if (r.length < 1)
601 				return (ISC_R_NOSPACE);
602 			r.base[0] = '\n';
603 			isc_buffer_add(target, 1);
604 		}
605 
606 		first = ISC_FALSE;
607 		result = dns_rdataset_next(rdataset);
608 	}
609 
610 	if (result != ISC_R_NOMORE)
611 		return (result);
612 
613 	/*
614 	 * Update the ctx state to reflect what we just printed.
615 	 * This is done last, only when we are sure we will return
616 	 * success, because this function may be called multiple
617 	 * times with increasing buffer sizes until it succeeds,
618 	 * and failed attempts must not update the state prematurely.
619 	 */
620 	ctx->class_printed = ISC_TRUE;
621 	ctx->current_ttl= current_ttl;
622 	ctx->current_ttl_valid = current_ttl_valid;
623 
624 	return (ISC_R_SUCCESS);
625 }
626 
627 /*
628  * Print the name, type, and class of an empty rdataset,
629  * such as those used to represent the question section
630  * of a DNS message.
631  */
632 static isc_result_t
633 question_totext(dns_rdataset_t *rdataset,
634 		dns_name_t *owner_name,
635 		dns_totext_ctx_t *ctx,
636 		isc_boolean_t omit_final_dot,
637 		isc_buffer_t *target)
638 {
639 	unsigned int column;
640 	isc_result_t result;
641 	isc_region_t r;
642 
643 	REQUIRE(DNS_RDATASET_VALID(rdataset));
644 	result = dns_rdataset_first(rdataset);
645 	REQUIRE(result == ISC_R_NOMORE);
646 
647 	column = 0;
648 
649 	/* Owner name */
650 	{
651 		unsigned int name_start = target->used;
652 		RETERR(dns_name_totext(owner_name,
653 				       omit_final_dot,
654 				       target));
655 		column += target->used - name_start;
656 	}
657 
658 	/* Class */
659 	{
660 		unsigned int class_start;
661 		INDENT_TO(class_column);
662 		class_start = target->used;
663 		result = dns_rdataclass_totext(rdataset->rdclass, target);
664 		if (result != ISC_R_SUCCESS)
665 			return (result);
666 		column += (target->used - class_start);
667 	}
668 
669 	/* Type */
670 	{
671 		unsigned int type_start;
672 		INDENT_TO(type_column);
673 		type_start = target->used;
674 		result = dns_rdatatype_totext(rdataset->type, target);
675 		if (result != ISC_R_SUCCESS)
676 			return (result);
677 		column += (target->used - type_start);
678 	}
679 
680 	isc_buffer_availableregion(target, &r);
681 	if (r.length < 1)
682 		return (ISC_R_NOSPACE);
683 	r.base[0] = '\n';
684 	isc_buffer_add(target, 1);
685 
686 	return (ISC_R_SUCCESS);
687 }
688 
689 isc_result_t
690 dns_rdataset_totext(dns_rdataset_t *rdataset,
691 		    dns_name_t *owner_name,
692 		    isc_boolean_t omit_final_dot,
693 		    isc_boolean_t question,
694 		    isc_buffer_t *target)
695 {
696 	dns_totext_ctx_t ctx;
697 	isc_result_t result;
698 	result = totext_ctx_init(&dns_master_style_debug, &ctx);
699 	if (result != ISC_R_SUCCESS) {
700 		UNEXPECTED_ERROR(__FILE__, __LINE__,
701 				 "could not set master file style");
702 		return (ISC_R_UNEXPECTED);
703 	}
704 
705 	/*
706 	 * The caller might want to give us an empty owner
707 	 * name (e.g. if they are outputting into a master
708 	 * file and this rdataset has the same name as the
709 	 * previous one.)
710 	 */
711 	if (dns_name_countlabels(owner_name) == 0)
712 		owner_name = NULL;
713 
714 	if (question)
715 		return (question_totext(rdataset, owner_name, &ctx,
716 					omit_final_dot, target));
717 	else
718 		return (rdataset_totext(rdataset, owner_name, &ctx,
719 					omit_final_dot, target));
720 }
721 
722 isc_result_t
723 dns_master_rdatasettotext(dns_name_t *owner_name,
724 			  dns_rdataset_t *rdataset,
725 			  const dns_master_style_t *style,
726 			  isc_buffer_t *target)
727 {
728 	dns_totext_ctx_t ctx;
729 	isc_result_t result;
730 	result = totext_ctx_init(style, &ctx);
731 	if (result != ISC_R_SUCCESS) {
732 		UNEXPECTED_ERROR(__FILE__, __LINE__,
733 				 "could not set master file style");
734 		return (ISC_R_UNEXPECTED);
735 	}
736 
737 	return (rdataset_totext(rdataset, owner_name, &ctx,
738 				ISC_FALSE, target));
739 }
740 
741 isc_result_t
742 dns_master_questiontotext(dns_name_t *owner_name,
743 			  dns_rdataset_t *rdataset,
744 			  const dns_master_style_t *style,
745 			  isc_buffer_t *target)
746 {
747 	dns_totext_ctx_t ctx;
748 	isc_result_t result;
749 	result = totext_ctx_init(style, &ctx);
750 	if (result != ISC_R_SUCCESS) {
751 		UNEXPECTED_ERROR(__FILE__, __LINE__,
752 				 "could not set master file style");
753 		return (ISC_R_UNEXPECTED);
754 	}
755 
756 	return (question_totext(rdataset, owner_name, &ctx,
757 				ISC_FALSE, target));
758 }
759 
760 /*
761  * Print an rdataset.  'buffer' is a scratch buffer, which must have been
762  * dynamically allocated by the caller.  It must be large enough to
763  * hold the result from dns_ttl_totext().  If more than that is needed,
764  * the buffer will be grown automatically.
765  */
766 
767 static isc_result_t
768 dump_rdataset(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
769 	      dns_totext_ctx_t *ctx,
770 	      isc_buffer_t *buffer, FILE *f)
771 {
772 	isc_region_t r;
773 	isc_result_t result;
774 
775 	REQUIRE(buffer->length > 0);
776 
777 	/*
778 	 * Output a $TTL directive if needed.
779 	 */
780 
781 	if ((ctx->style.flags & DNS_STYLEFLAG_TTL) != 0) {
782 		if (ctx->current_ttl_valid == ISC_FALSE ||
783 		    ctx->current_ttl != rdataset->ttl)
784 		{
785 			if ((ctx->style.flags & DNS_STYLEFLAG_COMMENT) != 0)
786 			{
787 				isc_buffer_clear(buffer);
788 				result = dns_ttl_totext(rdataset->ttl,
789 							ISC_TRUE, buffer);
790 				INSIST(result == ISC_R_SUCCESS);
791 				isc_buffer_usedregion(buffer, &r);
792 				fprintf(f, "$TTL %u\t; %.*s\n", rdataset->ttl,
793 					(int) r.length, (char *) r.base);
794 			} else {
795 				fprintf(f, "$TTL %u\n", rdataset->ttl);
796 			}
797 			ctx->current_ttl = rdataset->ttl;
798 			ctx->current_ttl_valid = ISC_TRUE;
799 		}
800 	}
801 
802 	isc_buffer_clear(buffer);
803 
804 	/*
805 	 * Generate the text representation of the rdataset into
806 	 * the buffer.  If the buffer is too small, grow it.
807 	 */
808 	for (;;) {
809 		int newlength;
810 		void *newmem;
811 		result = rdataset_totext(rdataset, name, ctx,
812 					 ISC_FALSE, buffer);
813 		if (result != ISC_R_NOSPACE)
814 			break;
815 
816 		newlength = buffer->length * 2;
817 		newmem = isc_mem_get(mctx, newlength);
818 		if (newmem == NULL)
819 			return (ISC_R_NOMEMORY);
820 		isc_mem_put(mctx, buffer->base, buffer->length);
821 		isc_buffer_init(buffer, newmem, newlength);
822 	}
823 	if (result != ISC_R_SUCCESS)
824 		return (result);
825 
826 	/*
827 	 * Write the buffer contents to the master file.
828 	 */
829 	isc_buffer_usedregion(buffer, &r);
830 	result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
831 
832 	if (result != ISC_R_SUCCESS) {
833 		UNEXPECTED_ERROR(__FILE__, __LINE__,
834 				 "master file write failed: %s",
835 				 isc_result_totext(result));
836 		return (result);
837 	}
838 
839 	return (ISC_R_SUCCESS);
840 }
841 
842 /*
843  * Define the order in which rdatasets should be printed in zone
844  * files.  We will print SOA and NS records before others, SIGs
845  * immediately following the things they sign, and order everything
846  * else by RR number.  This is all just for aesthetics and
847  * compatibility with buggy software that expects the SOA to be first;
848  * the DNS specifications allow any order.
849  */
850 
851 static int
852 dump_order(const dns_rdataset_t *rds) {
853 	int t;
854 	int sig;
855 	if (rds->type == dns_rdatatype_rrsig) {
856 		t = rds->covers;
857 		sig = 1;
858 	} else {
859 		t = rds->type;
860 		sig = 0;
861 	}
862 	switch (t) {
863 	case dns_rdatatype_soa:
864 		t = 0;
865 		break;
866 	case dns_rdatatype_ns:
867 		t = 1;
868 		break;
869 	default:
870 		t += 2;
871 		break;
872 	}
873 	return (t << 1) + sig;
874 }
875 
876 static int
877 dump_order_compare(const void *a, const void *b) {
878 	return (dump_order(*((const dns_rdataset_t * const *) a)) -
879 		dump_order(*((const dns_rdataset_t * const *) b)));
880 }
881 
882 /*
883  * Dump all the rdatasets of a domain name to a master file.  We make
884  * a "best effort" attempt to sort the RRsets in a nice order, but if
885  * there are more than MAXSORT RRsets, we punt and only sort them in
886  * groups of MAXSORT.  This is not expected to ever happen in practice
887  * since much less than 64 RR types have been registered with the
888  * IANA, so far, and the output will be correct (though not
889  * aesthetically pleasing) even if it does happen.
890  */
891 
892 #define MAXSORT 64
893 
894 static isc_result_t
895 dump_rdatasets_text(isc_mem_t *mctx, dns_name_t *name,
896 		    dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
897 		    isc_buffer_t *buffer, FILE *f)
898 {
899 	isc_result_t itresult, dumpresult;
900 	isc_region_t r;
901 	dns_rdataset_t rdatasets[MAXSORT];
902 	dns_rdataset_t *sorted[MAXSORT];
903 	int i, n;
904 
905 	itresult = dns_rdatasetiter_first(rdsiter);
906 	dumpresult = ISC_R_SUCCESS;
907 
908 	if (itresult == ISC_R_SUCCESS && ctx->neworigin != NULL) {
909 		isc_buffer_clear(buffer);
910 		itresult = dns_name_totext(ctx->neworigin, ISC_FALSE, buffer);
911 		RUNTIME_CHECK(itresult == ISC_R_SUCCESS);
912 		isc_buffer_usedregion(buffer, &r);
913 		fprintf(f, "$ORIGIN %.*s\n", (int) r.length, (char *) r.base);
914 		ctx->neworigin = NULL;
915 	}
916 
917  again:
918 	for (i = 0;
919 	     itresult == ISC_R_SUCCESS && i < MAXSORT;
920 	     itresult = dns_rdatasetiter_next(rdsiter), i++) {
921 		dns_rdataset_init(&rdatasets[i]);
922 		dns_rdatasetiter_current(rdsiter, &rdatasets[i]);
923 		sorted[i] = &rdatasets[i];
924 	}
925 	n = i;
926 	INSIST(n <= MAXSORT);
927 
928 	qsort(sorted, n, sizeof(sorted[0]), dump_order_compare);
929 
930 	for (i = 0; i < n; i++) {
931 		dns_rdataset_t *rds = sorted[i];
932 		if (ctx->style.flags & DNS_STYLEFLAG_TRUST)
933 			fprintf(f, "; %s\n", dns_trust_totext(rds->trust));
934 		if (((rds->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
935 		    (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
936 			/* Omit negative cache entries */
937 		} else {
938 			isc_result_t result =
939 				dump_rdataset(mctx, name, rds, ctx,
940 					       buffer, f);
941 			if (result != ISC_R_SUCCESS)
942 				dumpresult = result;
943 			if ((ctx->style.flags & DNS_STYLEFLAG_OMIT_OWNER) != 0)
944 				name = NULL;
945 		}
946 		if (ctx->style.flags & DNS_STYLEFLAG_RESIGN &&
947 		    rds->attributes & DNS_RDATASETATTR_RESIGN) {
948 			isc_buffer_t b;
949 			char buf[sizeof("YYYYMMDDHHMMSS")];
950 			memset(buf, 0, sizeof(buf));
951 			isc_buffer_init(&b, buf, sizeof(buf) - 1);
952 			dns_time64_totext((isc_uint64_t)rds->resign, &b);
953 			fprintf(f, "; resign=%s\n", buf);
954 		}
955 		dns_rdataset_disassociate(rds);
956 	}
957 
958 	if (dumpresult != ISC_R_SUCCESS)
959 		return (dumpresult);
960 
961 	/*
962 	 * If we got more data than could be sorted at once,
963 	 * go handle the rest.
964 	 */
965 	if (itresult == ISC_R_SUCCESS)
966 		goto again;
967 
968 	if (itresult == ISC_R_NOMORE)
969 		itresult = ISC_R_SUCCESS;
970 
971 	return (itresult);
972 }
973 
974 /*
975  * Dump given RRsets in the "raw" format.
976  */
977 static isc_result_t
978 dump_rdataset_raw(isc_mem_t *mctx, dns_name_t *name, dns_rdataset_t *rdataset,
979 		  isc_buffer_t *buffer, FILE *f)
980 {
981 	isc_result_t result;
982 	isc_uint32_t totallen;
983 	isc_uint16_t dlen;
984 	isc_region_t r, r_hdr;
985 
986 	REQUIRE(buffer->length > 0);
987 	REQUIRE(DNS_RDATASET_VALID(rdataset));
988 
989 	rdataset->attributes |= DNS_RDATASETATTR_LOADORDER;
990  restart:
991 	totallen = 0;
992 	result = dns_rdataset_first(rdataset);
993 	REQUIRE(result == ISC_R_SUCCESS);
994 
995 	isc_buffer_clear(buffer);
996 
997 	/*
998 	 * Common header and owner name (length followed by name)
999 	 * These fields should be in a moderate length, so we assume we
1000 	 * can store all of them in the initial buffer.
1001 	 */
1002 	isc_buffer_availableregion(buffer, &r_hdr);
1003 	INSIST(r_hdr.length >= sizeof(dns_masterrawrdataset_t));
1004 	isc_buffer_putuint32(buffer, totallen);	/* XXX: leave space */
1005 	isc_buffer_putuint16(buffer, rdataset->rdclass); /* 16-bit class */
1006 	isc_buffer_putuint16(buffer, rdataset->type); /* 16-bit type */
1007 	isc_buffer_putuint16(buffer, rdataset->covers);	/* same as type */
1008 	isc_buffer_putuint32(buffer, rdataset->ttl); /* 32-bit TTL */
1009 	isc_buffer_putuint32(buffer, dns_rdataset_count(rdataset));
1010 	totallen = isc_buffer_usedlength(buffer);
1011 	INSIST(totallen <= sizeof(dns_masterrawrdataset_t));
1012 
1013 	dns_name_toregion(name, &r);
1014 	INSIST(isc_buffer_availablelength(buffer) >=
1015 	       (sizeof(dlen) + r.length));
1016 	dlen = (isc_uint16_t)r.length;
1017 	isc_buffer_putuint16(buffer, dlen);
1018 	isc_buffer_copyregion(buffer, &r);
1019 	totallen += sizeof(dlen) + r.length;
1020 
1021 	do {
1022 		dns_rdata_t rdata = DNS_RDATA_INIT;
1023 
1024 		dns_rdataset_current(rdataset, &rdata);
1025 		dns_rdata_toregion(&rdata, &r);
1026 		INSIST(r.length <= 0xffffU);
1027 		dlen = (isc_uint16_t)r.length;
1028 
1029 		/*
1030 		 * Copy the rdata into the buffer.  If the buffer is too small,
1031 		 * grow it.  This should be rare, so we'll simply restart the
1032 		 * entire procedure (or should we copy the old data and
1033 		 * continue?).
1034 		 */
1035 		if (isc_buffer_availablelength(buffer) <
1036 						 sizeof(dlen) + r.length) {
1037 			int newlength;
1038 			void *newmem;
1039 
1040 			newlength = buffer->length * 2;
1041 			newmem = isc_mem_get(mctx, newlength);
1042 			if (newmem == NULL)
1043 				return (ISC_R_NOMEMORY);
1044 			isc_mem_put(mctx, buffer->base, buffer->length);
1045 			isc_buffer_init(buffer, newmem, newlength);
1046 			goto restart;
1047 		}
1048 		isc_buffer_putuint16(buffer, dlen);
1049 		isc_buffer_copyregion(buffer, &r);
1050 		totallen += sizeof(dlen) + r.length;
1051 
1052 		result = dns_rdataset_next(rdataset);
1053 	} while (result == ISC_R_SUCCESS);
1054 
1055 	if (result != ISC_R_NOMORE)
1056 		return (result);
1057 
1058 	/*
1059 	 * Fill in the total length field.
1060 	 * XXX: this is a bit tricky.  Since we have already "used" the space
1061 	 * for the total length in the buffer, we first remember the entire
1062 	 * buffer length in the region, "rewind", and then write the value.
1063 	 */
1064 	isc_buffer_usedregion(buffer, &r);
1065 	isc_buffer_clear(buffer);
1066 	isc_buffer_putuint32(buffer, totallen);
1067 	INSIST(isc_buffer_usedlength(buffer) < totallen);
1068 
1069 	/*
1070 	 * Write the buffer contents to the raw master file.
1071 	 */
1072 	result = isc_stdio_write(r.base, 1, (size_t)r.length, f, NULL);
1073 
1074 	if (result != ISC_R_SUCCESS) {
1075 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1076 				 "raw master file write failed: %s",
1077 				 isc_result_totext(result));
1078 		return (result);
1079 	}
1080 
1081 	return (result);
1082 }
1083 
1084 static isc_result_t
1085 dump_rdatasets_raw(isc_mem_t *mctx, dns_name_t *name,
1086 		   dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
1087 		   isc_buffer_t *buffer, FILE *f)
1088 {
1089 	isc_result_t result;
1090 	dns_rdataset_t rdataset;
1091 
1092 	for (result = dns_rdatasetiter_first(rdsiter);
1093 	     result == ISC_R_SUCCESS;
1094 	     result = dns_rdatasetiter_next(rdsiter)) {
1095 
1096 		dns_rdataset_init(&rdataset);
1097 		dns_rdatasetiter_current(rdsiter, &rdataset);
1098 
1099 		if (((rdataset.attributes & DNS_RDATASETATTR_NEGATIVE) != 0) &&
1100 		    (ctx->style.flags & DNS_STYLEFLAG_NCACHE) == 0) {
1101 			/* Omit negative cache entries */
1102 		} else {
1103 			result = dump_rdataset_raw(mctx, name, &rdataset,
1104 						   buffer, f);
1105 		}
1106 		dns_rdataset_disassociate(&rdataset);
1107 		if (result != ISC_R_SUCCESS)
1108 			return (result);
1109 	}
1110 
1111 	if (result == ISC_R_NOMORE)
1112 		result = ISC_R_SUCCESS;
1113 
1114 	return (result);
1115 }
1116 
1117 static isc_result_t
1118 dump_rdatasets_map(isc_mem_t *mctx, dns_name_t *name,
1119 		   dns_rdatasetiter_t *rdsiter, dns_totext_ctx_t *ctx,
1120 		   isc_buffer_t *buffer, FILE *f)
1121 {
1122 	UNUSED(mctx);
1123 	UNUSED(name);
1124 	UNUSED(rdsiter);
1125 	UNUSED(ctx);
1126 	UNUSED(buffer);
1127 	UNUSED(f);
1128 
1129 	return (ISC_R_NOTIMPLEMENTED);
1130 }
1131 
1132 /*
1133  * Initial size of text conversion buffer.  The buffer is used
1134  * for several purposes: converting origin names, rdatasets,
1135  * $DATE timestamps, and comment strings for $TTL directives.
1136  *
1137  * When converting rdatasets, it is dynamically resized, but
1138  * when converting origins, timestamps, etc it is not.  Therefore,
1139  * the initial size must large enough to hold the longest possible
1140  * text representation of any domain name (for $ORIGIN).
1141  */
1142 static const int initial_buffer_length = 1200;
1143 
1144 static isc_result_t
1145 dumptostreaminc(dns_dumpctx_t *dctx);
1146 
1147 static void
1148 dumpctx_destroy(dns_dumpctx_t *dctx) {
1149 
1150 	dctx->magic = 0;
1151 	DESTROYLOCK(&dctx->lock);
1152 	dns_dbiterator_destroy(&dctx->dbiter);
1153 	if (dctx->version != NULL)
1154 		dns_db_closeversion(dctx->db, &dctx->version, ISC_FALSE);
1155 	dns_db_detach(&dctx->db);
1156 	if (dctx->task != NULL)
1157 		isc_task_detach(&dctx->task);
1158 	if (dctx->file != NULL)
1159 		isc_mem_free(dctx->mctx, dctx->file);
1160 	if (dctx->tmpfile != NULL)
1161 		isc_mem_free(dctx->mctx, dctx->tmpfile);
1162 	isc_mem_putanddetach(&dctx->mctx, dctx, sizeof(*dctx));
1163 }
1164 
1165 void
1166 dns_dumpctx_attach(dns_dumpctx_t *source, dns_dumpctx_t **target) {
1167 
1168 	REQUIRE(DNS_DCTX_VALID(source));
1169 	REQUIRE(target != NULL && *target == NULL);
1170 
1171 	LOCK(&source->lock);
1172 	INSIST(source->references > 0);
1173 	source->references++;
1174 	INSIST(source->references != 0);	/* Overflow? */
1175 	UNLOCK(&source->lock);
1176 
1177 	*target = source;
1178 }
1179 
1180 void
1181 dns_dumpctx_detach(dns_dumpctx_t **dctxp) {
1182 	dns_dumpctx_t *dctx;
1183 	isc_boolean_t need_destroy = ISC_FALSE;
1184 
1185 	REQUIRE(dctxp != NULL);
1186 	dctx = *dctxp;
1187 	REQUIRE(DNS_DCTX_VALID(dctx));
1188 
1189 	*dctxp = NULL;
1190 
1191 	LOCK(&dctx->lock);
1192 	INSIST(dctx->references != 0);
1193 	dctx->references--;
1194 	if (dctx->references == 0)
1195 		need_destroy = ISC_TRUE;
1196 	UNLOCK(&dctx->lock);
1197 	if (need_destroy)
1198 		dumpctx_destroy(dctx);
1199 }
1200 
1201 dns_dbversion_t *
1202 dns_dumpctx_version(dns_dumpctx_t *dctx) {
1203 	REQUIRE(DNS_DCTX_VALID(dctx));
1204 	return (dctx->version);
1205 }
1206 
1207 dns_db_t *
1208 dns_dumpctx_db(dns_dumpctx_t *dctx) {
1209 	REQUIRE(DNS_DCTX_VALID(dctx));
1210 	return (dctx->db);
1211 }
1212 
1213 void
1214 dns_dumpctx_cancel(dns_dumpctx_t *dctx) {
1215 	REQUIRE(DNS_DCTX_VALID(dctx));
1216 
1217 	LOCK(&dctx->lock);
1218 	dctx->canceled = ISC_TRUE;
1219 	UNLOCK(&dctx->lock);
1220 }
1221 
1222 static isc_result_t
1223 flushandsync(FILE *f, isc_result_t result, const char *temp) {
1224 	isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
1225 
1226 	if (result == ISC_R_SUCCESS)
1227 		result = isc_stdio_flush(f);
1228 	if (result != ISC_R_SUCCESS && logit) {
1229 		if (temp != NULL)
1230 			isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1231 				      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1232 				      "dumping to master file: %s: flush: %s",
1233 				      temp, isc_result_totext(result));
1234 		else
1235 			isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1236 				      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1237 				      "dumping to stream: flush: %s",
1238 				      isc_result_totext(result));
1239 		logit = ISC_FALSE;
1240 	}
1241 
1242 	if (result == ISC_R_SUCCESS)
1243 		result = isc_stdio_sync(f);
1244 	if (result != ISC_R_SUCCESS && logit) {
1245 		if (temp != NULL)
1246 			isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1247 				      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1248 				      "dumping to master file: %s: fsync: %s",
1249 				      temp, isc_result_totext(result));
1250 		else
1251 			isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1252 				      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1253 				      "dumping to stream: fsync: %s",
1254 				      isc_result_totext(result));
1255 	}
1256 	return (result);
1257 }
1258 
1259 static isc_result_t
1260 closeandrename(FILE *f, isc_result_t result, const char *temp, const char *file)
1261 {
1262 	isc_result_t tresult;
1263 	isc_boolean_t logit = ISC_TF(result == ISC_R_SUCCESS);
1264 
1265 	result = flushandsync(f, result, temp);
1266 	if (result != ISC_R_SUCCESS)
1267 		logit = ISC_FALSE;
1268 
1269 	tresult = isc_stdio_close(f);
1270 	if (result == ISC_R_SUCCESS)
1271 		result = tresult;
1272 	if (result != ISC_R_SUCCESS && logit) {
1273 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1274 			      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1275 			      "dumping master file: %s: fclose: %s",
1276 			      temp, isc_result_totext(result));
1277 		logit = ISC_FALSE;
1278 	}
1279 	if (result == ISC_R_SUCCESS)
1280 		result = isc_file_rename(temp, file);
1281 	else
1282 		(void)isc_file_remove(temp);
1283 	if (result != ISC_R_SUCCESS && logit) {
1284 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1285 			      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1286 			      "dumping master file: rename: %s: %s",
1287 			      file, isc_result_totext(result));
1288 	}
1289 	return (result);
1290 }
1291 
1292 static void
1293 dump_quantum(isc_task_t *task, isc_event_t *event) {
1294 	isc_result_t result;
1295 	isc_result_t tresult;
1296 	dns_dumpctx_t *dctx;
1297 
1298 	REQUIRE(event != NULL);
1299 	dctx = event->ev_arg;
1300 	REQUIRE(DNS_DCTX_VALID(dctx));
1301 	if (dctx->canceled)
1302 		result = ISC_R_CANCELED;
1303 	else
1304 		result = dumptostreaminc(dctx);
1305 	if (result == DNS_R_CONTINUE) {
1306 		event->ev_arg = dctx;
1307 		isc_task_send(task, &event);
1308 		return;
1309 	}
1310 
1311 	if (dctx->file != NULL) {
1312 		tresult = closeandrename(dctx->f, result,
1313 					 dctx->tmpfile, dctx->file);
1314 		if (tresult != ISC_R_SUCCESS && result == ISC_R_SUCCESS)
1315 			result = tresult;
1316 	} else
1317 		result = flushandsync(dctx->f, result, NULL);
1318 	(dctx->done)(dctx->done_arg, result);
1319 	isc_event_free(&event);
1320 	dns_dumpctx_detach(&dctx);
1321 }
1322 
1323 static isc_result_t
1324 task_send(dns_dumpctx_t *dctx) {
1325 	isc_event_t *event;
1326 
1327 	event = isc_event_allocate(dctx->mctx, NULL, DNS_EVENT_DUMPQUANTUM,
1328 				   dump_quantum, dctx, sizeof(*event));
1329 	if (event == NULL)
1330 		return (ISC_R_NOMEMORY);
1331 	isc_task_send(dctx->task, &event);
1332 	return (ISC_R_SUCCESS);
1333 }
1334 
1335 static isc_result_t
1336 dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1337 	       const dns_master_style_t *style, FILE *f, dns_dumpctx_t **dctxp,
1338 	       dns_masterformat_t format, dns_masterrawheader_t *header)
1339 {
1340 	dns_dumpctx_t *dctx;
1341 	isc_result_t result;
1342 	unsigned int options;
1343 
1344 	dctx = isc_mem_get(mctx, sizeof(*dctx));
1345 	if (dctx == NULL)
1346 		return (ISC_R_NOMEMORY);
1347 
1348 	dctx->mctx = NULL;
1349 	dctx->f = f;
1350 	dctx->dbiter = NULL;
1351 	dctx->db = NULL;
1352 	dctx->version = NULL;
1353 	dctx->done = NULL;
1354 	dctx->done_arg = NULL;
1355 	dctx->task = NULL;
1356 	dctx->nodes = 0;
1357 	dctx->first = ISC_TRUE;
1358 	dctx->canceled = ISC_FALSE;
1359 	dctx->file = NULL;
1360 	dctx->tmpfile = NULL;
1361 	dctx->format = format;
1362 	if (header == NULL)
1363 		dns_master_initrawheader(&dctx->header);
1364 	else
1365 		dctx->header = *header;
1366 
1367 	switch (format) {
1368 	case dns_masterformat_text:
1369 		dctx->dumpsets = dump_rdatasets_text;
1370 		break;
1371 	case dns_masterformat_raw:
1372 		dctx->dumpsets = dump_rdatasets_raw;
1373 		break;
1374 	case dns_masterformat_map:
1375 		dctx->dumpsets = dump_rdatasets_map;
1376 		break;
1377 	default:
1378 		INSIST(0);
1379 		break;
1380 	}
1381 
1382 	result = totext_ctx_init(style, &dctx->tctx);
1383 	if (result != ISC_R_SUCCESS) {
1384 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1385 				 "could not set master file style");
1386 		goto cleanup;
1387 	}
1388 
1389 	isc_stdtime_get(&dctx->now);
1390 	dns_db_attach(db, &dctx->db);
1391 
1392 	dctx->do_date = dns_db_iscache(dctx->db);
1393 
1394 	if (dctx->format == dns_masterformat_text &&
1395 	    (dctx->tctx.style.flags & DNS_STYLEFLAG_REL_OWNER) != 0) {
1396 		options = DNS_DB_RELATIVENAMES;
1397 	} else
1398 		options = 0;
1399 	result = dns_db_createiterator(dctx->db, options, &dctx->dbiter);
1400 	if (result != ISC_R_SUCCESS)
1401 		goto cleanup;
1402 
1403 	result = isc_mutex_init(&dctx->lock);
1404 	if (result != ISC_R_SUCCESS)
1405 		goto cleanup;
1406 	if (version != NULL)
1407 		dns_db_attachversion(dctx->db, version, &dctx->version);
1408 	else if (!dns_db_iscache(db))
1409 		dns_db_currentversion(dctx->db, &dctx->version);
1410 	isc_mem_attach(mctx, &dctx->mctx);
1411 	dctx->references = 1;
1412 	dctx->magic = DNS_DCTX_MAGIC;
1413 	*dctxp = dctx;
1414 	return (ISC_R_SUCCESS);
1415 
1416  cleanup:
1417 	if (dctx->dbiter != NULL)
1418 		dns_dbiterator_destroy(&dctx->dbiter);
1419 	if (dctx->db != NULL)
1420 		dns_db_detach(&dctx->db);
1421 	if (dctx != NULL)
1422 		isc_mem_put(mctx, dctx, sizeof(*dctx));
1423 	return (result);
1424 }
1425 
1426 static isc_result_t
1427 writeheader(dns_dumpctx_t *dctx) {
1428 	isc_result_t result = ISC_R_SUCCESS;
1429 	isc_buffer_t buffer;
1430 	char *bufmem;
1431 	isc_region_t r;
1432 	dns_masterrawheader_t rawheader;
1433 	isc_uint32_t rawversion, now32;
1434 
1435 	bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
1436 	if (bufmem == NULL)
1437 		return (ISC_R_NOMEMORY);
1438 
1439 	isc_buffer_init(&buffer, bufmem, initial_buffer_length);
1440 
1441 	switch (dctx->format) {
1442 	case dns_masterformat_text:
1443 		/*
1444 		 * If the database has cache semantics, output an
1445 		 * RFC2540 $DATE directive so that the TTLs can be
1446 		 * adjusted when it is reloaded.  For zones it is not
1447 		 * really needed, and it would make the file
1448 		 * incompatible with pre-RFC2540 software, so we omit
1449 		 * it in the zone case.
1450 		 */
1451 		if (dctx->do_date) {
1452 			result = dns_time32_totext(dctx->now, &buffer);
1453 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
1454 			isc_buffer_usedregion(&buffer, &r);
1455 			fprintf(dctx->f, "$DATE %.*s\n",
1456 				(int) r.length, (char *) r.base);
1457 		}
1458 		break;
1459 	case dns_masterformat_raw:
1460 	case dns_masterformat_map:
1461 		r.base = (unsigned char *)&rawheader;
1462 		r.length = sizeof(rawheader);
1463 		isc_buffer_region(&buffer, &r);
1464 #if !defined(STDTIME_ON_32BITS) || (STDTIME_ON_32BITS + 0) != 1
1465 		/*
1466 		 * We assume isc_stdtime_t is a 32-bit integer,
1467 		 * which should be the case on most platforms.
1468 		 * If it turns out to be uncommon, we'll need
1469 		 * to bump the version number and revise the
1470 		 * header format.
1471 		 */
1472 		isc_log_write(dns_lctx,
1473 			      ISC_LOGCATEGORY_GENERAL,
1474 			      DNS_LOGMODULE_MASTERDUMP,
1475 			      ISC_LOG_INFO,
1476 			      "dumping master file in raw "
1477 			      "format: stdtime is not 32bits");
1478 		now32 = 0;
1479 #else
1480 		now32 = dctx->now;
1481 #endif
1482 		rawversion = 1;
1483 		if ((dctx->header.flags & DNS_MASTERRAW_COMPAT) != 0)
1484 			rawversion = 0;
1485 
1486 		isc_buffer_putuint32(&buffer, dctx->format);
1487 		isc_buffer_putuint32(&buffer, rawversion);
1488 		isc_buffer_putuint32(&buffer, now32);
1489 
1490 		if (rawversion == 1) {
1491 			isc_buffer_putuint32(&buffer, dctx->header.flags);
1492 			isc_buffer_putuint32(&buffer,
1493 					     dctx->header.sourceserial);
1494 			isc_buffer_putuint32(&buffer, dctx->header.lastxfrin);
1495 		}
1496 
1497 		INSIST(isc_buffer_usedlength(&buffer) <= sizeof(rawheader));
1498 		result = isc_stdio_write(buffer.base, 1,
1499 					 isc_buffer_usedlength(&buffer),
1500 					 dctx->f, NULL);
1501 		if (result != ISC_R_SUCCESS)
1502 			break;
1503 
1504 		break;
1505 	default:
1506 		INSIST(0);
1507 	}
1508 
1509 	isc_mem_put(dctx->mctx, buffer.base, buffer.length);
1510 	return (result);
1511 }
1512 
1513 static isc_result_t
1514 dumptostreaminc(dns_dumpctx_t *dctx) {
1515 	isc_result_t result = ISC_R_SUCCESS;
1516 	isc_buffer_t buffer;
1517 	char *bufmem;
1518 	dns_name_t *name;
1519 	dns_fixedname_t fixname;
1520 	unsigned int nodes;
1521 	isc_time_t start;
1522 
1523 	bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
1524 	if (bufmem == NULL)
1525 		return (ISC_R_NOMEMORY);
1526 
1527 	isc_buffer_init(&buffer, bufmem, initial_buffer_length);
1528 
1529 	dns_fixedname_init(&fixname);
1530 	name = dns_fixedname_name(&fixname);
1531 
1532 	if (dctx->first) {
1533 		CHECK(writeheader(dctx));
1534 
1535 		/*
1536 		 * Fast format is not currently written incrementally,
1537 		 * so we make the call to dns_db_serialize() here.
1538 		 * If the database is anything other than an rbtdb,
1539 		 * this should result in not implemented
1540 		 */
1541 		if (dctx->format == dns_masterformat_map) {
1542 			result = dns_db_serialize(dctx->db, dctx->version,
1543 						  dctx->f);
1544 			goto cleanup;
1545 		}
1546 
1547 		result = dns_dbiterator_first(dctx->dbiter);
1548 		if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE)
1549 			goto cleanup;
1550 
1551 		dctx->first = ISC_FALSE;
1552 	} else
1553 		result = ISC_R_SUCCESS;
1554 
1555 	nodes = dctx->nodes;
1556 	isc_time_now(&start);
1557 	while (result == ISC_R_SUCCESS && (dctx->nodes == 0 || nodes--)) {
1558 		dns_rdatasetiter_t *rdsiter = NULL;
1559 		dns_dbnode_t *node = NULL;
1560 
1561 		result = dns_dbiterator_current(dctx->dbiter, &node, name);
1562 		if (result != ISC_R_SUCCESS && result != DNS_R_NEWORIGIN)
1563 			break;
1564 		if (result == DNS_R_NEWORIGIN) {
1565 			dns_name_t *origin =
1566 				dns_fixedname_name(&dctx->tctx.origin_fixname);
1567 			result = dns_dbiterator_origin(dctx->dbiter, origin);
1568 			RUNTIME_CHECK(result == ISC_R_SUCCESS);
1569 			if ((dctx->tctx.style.flags &
1570 			     DNS_STYLEFLAG_REL_DATA) != 0)
1571 				dctx->tctx.origin = origin;
1572 			dctx->tctx.neworigin = origin;
1573 		}
1574 		result = dns_db_allrdatasets(dctx->db, node, dctx->version,
1575 					     dctx->now, &rdsiter);
1576 		if (result != ISC_R_SUCCESS) {
1577 			dns_db_detachnode(dctx->db, &node);
1578 			goto cleanup;
1579 		}
1580 		result = (dctx->dumpsets)(dctx->mctx, name, rdsiter,
1581 					  &dctx->tctx, &buffer, dctx->f);
1582 		dns_rdatasetiter_destroy(&rdsiter);
1583 		if (result != ISC_R_SUCCESS) {
1584 			dns_db_detachnode(dctx->db, &node);
1585 			goto cleanup;
1586 		}
1587 		dns_db_detachnode(dctx->db, &node);
1588 		result = dns_dbiterator_next(dctx->dbiter);
1589 	}
1590 
1591 	/*
1592 	 * Work out how many nodes can be written in the time between
1593 	 * two requests to the nameserver.  Smooth the resulting number and
1594 	 * use it as a estimate for the number of nodes to be written in the
1595 	 * next iteration.
1596 	 */
1597 	if (dctx->nodes != 0 && result == ISC_R_SUCCESS) {
1598 		unsigned int pps = dns_pps;	/* packets per second */
1599 		unsigned int interval;
1600 		isc_uint64_t usecs;
1601 		isc_time_t end;
1602 
1603 		isc_time_now(&end);
1604 		if (pps < 100)
1605 			pps = 100;
1606 		interval = 1000000 / pps;	/* interval in usecs */
1607 		if (interval == 0)
1608 			interval = 1;
1609 		usecs = isc_time_microdiff(&end, &start);
1610 		if (usecs == 0) {
1611 			dctx->nodes = dctx->nodes * 2;
1612 			if (dctx->nodes > 1000)
1613 				dctx->nodes = 1000;
1614 		} else {
1615 			nodes = dctx->nodes * interval;
1616 			nodes /= (unsigned int)usecs;
1617 			if (nodes == 0)
1618 				nodes = 1;
1619 			else if (nodes > 1000)
1620 				nodes = 1000;
1621 
1622 			/* Smooth and assign. */
1623 			dctx->nodes = (nodes + dctx->nodes * 7) / 8;
1624 
1625 			isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1626 				      DNS_LOGMODULE_MASTERDUMP,
1627 				      ISC_LOG_DEBUG(1),
1628 				      "dumptostreaminc(%p) new nodes -> %d\n",
1629 				      dctx, dctx->nodes);
1630 		}
1631 		result = DNS_R_CONTINUE;
1632 	} else if (result == ISC_R_NOMORE)
1633 		result = ISC_R_SUCCESS;
1634  cleanup:
1635 	RUNTIME_CHECK(dns_dbiterator_pause(dctx->dbiter) == ISC_R_SUCCESS);
1636 	isc_mem_put(dctx->mctx, buffer.base, buffer.length);
1637 	return (result);
1638 }
1639 
1640 isc_result_t
1641 dns_master_dumptostreaminc(isc_mem_t *mctx, dns_db_t *db,
1642 			   dns_dbversion_t *version,
1643 			   const dns_master_style_t *style,
1644 			   FILE *f, isc_task_t *task,
1645 			   dns_dumpdonefunc_t done, void *done_arg,
1646 			   dns_dumpctx_t **dctxp)
1647 {
1648 	dns_dumpctx_t *dctx = NULL;
1649 	isc_result_t result;
1650 
1651 	REQUIRE(task != NULL);
1652 	REQUIRE(f != NULL);
1653 	REQUIRE(done != NULL);
1654 
1655 	result = dumpctx_create(mctx, db, version, style, f, &dctx,
1656 				dns_masterformat_text, NULL);
1657 	if (result != ISC_R_SUCCESS)
1658 		return (result);
1659 	isc_task_attach(task, &dctx->task);
1660 	dctx->done = done;
1661 	dctx->done_arg = done_arg;
1662 	dctx->nodes = 100;
1663 
1664 	result = task_send(dctx);
1665 	if (result == ISC_R_SUCCESS) {
1666 		dns_dumpctx_attach(dctx, dctxp);
1667 		return (DNS_R_CONTINUE);
1668 	}
1669 
1670 	dns_dumpctx_detach(&dctx);
1671 	return (result);
1672 }
1673 
1674 /*
1675  * Dump an entire database into a master file.
1676  */
1677 isc_result_t
1678 dns_master_dumptostream(isc_mem_t *mctx, dns_db_t *db,
1679 			dns_dbversion_t *version,
1680 			const dns_master_style_t *style,
1681 			FILE *f)
1682 {
1683 	return (dns_master_dumptostream3(mctx, db, version, style,
1684 					 dns_masterformat_text, NULL, f));
1685 }
1686 
1687 isc_result_t
1688 dns_master_dumptostream2(isc_mem_t *mctx, dns_db_t *db,
1689 			 dns_dbversion_t *version,
1690 			 const dns_master_style_t *style,
1691 			 dns_masterformat_t format, FILE *f)
1692 {
1693 	return (dns_master_dumptostream3(mctx, db, version, style,
1694 					 format, NULL, f));
1695 }
1696 
1697 isc_result_t
1698 dns_master_dumptostream3(isc_mem_t *mctx, dns_db_t *db,
1699 			 dns_dbversion_t *version,
1700 			 const dns_master_style_t *style,
1701 			 dns_masterformat_t format,
1702 			 dns_masterrawheader_t *header, FILE *f)
1703 {
1704 	dns_dumpctx_t *dctx = NULL;
1705 	isc_result_t result;
1706 
1707 	result = dumpctx_create(mctx, db, version, style, f, &dctx,
1708 				format, header);
1709 	if (result != ISC_R_SUCCESS)
1710 		return (result);
1711 
1712 	result = dumptostreaminc(dctx);
1713 	INSIST(result != DNS_R_CONTINUE);
1714 	dns_dumpctx_detach(&dctx);
1715 
1716 	result = flushandsync(f, result, NULL);
1717 	return (result);
1718 }
1719 
1720 static isc_result_t
1721 opentmp(isc_mem_t *mctx, dns_masterformat_t format, const char *file,
1722 	char **tempp, FILE **fp) {
1723 	FILE *f = NULL;
1724 	isc_result_t result;
1725 	char *tempname = NULL;
1726 	int tempnamelen;
1727 
1728 	tempnamelen = strlen(file) + 20;
1729 	tempname = isc_mem_allocate(mctx, tempnamelen);
1730 	if (tempname == NULL)
1731 		return (ISC_R_NOMEMORY);
1732 
1733 	result = isc_file_mktemplate(file, tempname, tempnamelen);
1734 	if (result != ISC_R_SUCCESS)
1735 		goto cleanup;
1736 
1737 	if (format == dns_masterformat_text)
1738 		result = isc_file_openunique(tempname, &f);
1739 	else
1740 		result = isc_file_bopenunique(tempname, &f);
1741 	if (result != ISC_R_SUCCESS) {
1742 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1743 			      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1744 			      "dumping master file: %s: open: %s",
1745 			      tempname, isc_result_totext(result));
1746 		goto cleanup;
1747 	}
1748 	*tempp = tempname;
1749 	*fp = f;
1750 	return (ISC_R_SUCCESS);
1751 
1752 cleanup:
1753 	isc_mem_free(mctx, tempname);
1754 	return (result);
1755 }
1756 
1757 isc_result_t
1758 dns_master_dumpinc(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1759 		   const dns_master_style_t *style, const char *filename,
1760 		   isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
1761 		   dns_dumpctx_t **dctxp)
1762 {
1763 	return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
1764 				    done, done_arg, dctxp,
1765 				    dns_masterformat_text, NULL));
1766 }
1767 
1768 isc_result_t
1769 dns_master_dumpinc2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1770 		    const dns_master_style_t *style, const char *filename,
1771 		    isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
1772 		    dns_dumpctx_t **dctxp, dns_masterformat_t format)
1773 {
1774 	return (dns_master_dumpinc3(mctx, db, version, style, filename, task,
1775 				    done, done_arg, dctxp, format, NULL));
1776 }
1777 
1778 isc_result_t
1779 dns_master_dumpinc3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1780 		    const dns_master_style_t *style, const char *filename,
1781 		    isc_task_t *task, dns_dumpdonefunc_t done, void *done_arg,
1782 		    dns_dumpctx_t **dctxp, dns_masterformat_t format,
1783 		    dns_masterrawheader_t *header)
1784 {
1785 	FILE *f = NULL;
1786 	isc_result_t result;
1787 	char *tempname = NULL;
1788 	char *file = NULL;
1789 	dns_dumpctx_t *dctx = NULL;
1790 
1791 	file = isc_mem_strdup(mctx, filename);
1792 	if (file == NULL)
1793 		return (ISC_R_NOMEMORY);
1794 
1795 	result = opentmp(mctx, format, filename, &tempname, &f);
1796 	if (result != ISC_R_SUCCESS)
1797 		goto cleanup;
1798 
1799 	result = dumpctx_create(mctx, db, version, style, f, &dctx,
1800 				format, header);
1801 	if (result != ISC_R_SUCCESS) {
1802 		(void)isc_stdio_close(f);
1803 		(void)isc_file_remove(tempname);
1804 		goto cleanup;
1805 	}
1806 
1807 	isc_task_attach(task, &dctx->task);
1808 	dctx->done = done;
1809 	dctx->done_arg = done_arg;
1810 	dctx->nodes = 100;
1811 	dctx->file = file;
1812 	file = NULL;
1813 	dctx->tmpfile = tempname;
1814 	tempname = NULL;
1815 
1816 	result = task_send(dctx);
1817 	if (result == ISC_R_SUCCESS) {
1818 		dns_dumpctx_attach(dctx, dctxp);
1819 		return (DNS_R_CONTINUE);
1820 	}
1821 
1822  cleanup:
1823 	if (dctx != NULL)
1824 		dns_dumpctx_detach(&dctx);
1825 	if (file != NULL)
1826 		isc_mem_free(mctx, file);
1827 	if (tempname != NULL)
1828 		isc_mem_free(mctx, tempname);
1829 	return (result);
1830 }
1831 
1832 isc_result_t
1833 dns_master_dump(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1834 		const dns_master_style_t *style, const char *filename)
1835 {
1836 	return (dns_master_dump3(mctx, db, version, style, filename,
1837 				 dns_masterformat_text, NULL));
1838 }
1839 
1840 isc_result_t
1841 dns_master_dump2(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1842 		 const dns_master_style_t *style, const char *filename,
1843 		 dns_masterformat_t format)
1844 {
1845 	return (dns_master_dump3(mctx, db, version, style, filename,
1846 				 format, NULL));
1847 }
1848 
1849 isc_result_t
1850 dns_master_dump3(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1851 		 const dns_master_style_t *style, const char *filename,
1852 		 dns_masterformat_t format, dns_masterrawheader_t *header)
1853 {
1854 	FILE *f = NULL;
1855 	isc_result_t result;
1856 	char *tempname;
1857 	dns_dumpctx_t *dctx = NULL;
1858 
1859 	result = opentmp(mctx, format, filename, &tempname, &f);
1860 	if (result != ISC_R_SUCCESS)
1861 		return (result);
1862 
1863 	result = dumpctx_create(mctx, db, version, style, f, &dctx,
1864 				format, header);
1865 	if (result != ISC_R_SUCCESS)
1866 		goto cleanup;
1867 
1868 	result = dumptostreaminc(dctx);
1869 	INSIST(result != DNS_R_CONTINUE);
1870 	dns_dumpctx_detach(&dctx);
1871 
1872 	result = closeandrename(f, result, tempname, filename);
1873 
1874  cleanup:
1875 	isc_mem_free(mctx, tempname);
1876 	return (result);
1877 }
1878 
1879 /*
1880  * Dump a database node into a master file.
1881  * XXX: this function assumes the text format.
1882  */
1883 isc_result_t
1884 dns_master_dumpnodetostream(isc_mem_t *mctx, dns_db_t *db,
1885 			    dns_dbversion_t *version,
1886 			    dns_dbnode_t *node, dns_name_t *name,
1887 			    const dns_master_style_t *style,
1888 			    FILE *f)
1889 {
1890 	isc_result_t result;
1891 	isc_buffer_t buffer;
1892 	char *bufmem;
1893 	isc_stdtime_t now;
1894 	dns_totext_ctx_t ctx;
1895 	dns_rdatasetiter_t *rdsiter = NULL;
1896 
1897 	result = totext_ctx_init(style, &ctx);
1898 	if (result != ISC_R_SUCCESS) {
1899 		UNEXPECTED_ERROR(__FILE__, __LINE__,
1900 				 "could not set master file style");
1901 		return (ISC_R_UNEXPECTED);
1902 	}
1903 
1904 	isc_stdtime_get(&now);
1905 
1906 	bufmem = isc_mem_get(mctx, initial_buffer_length);
1907 	if (bufmem == NULL)
1908 		return (ISC_R_NOMEMORY);
1909 
1910 	isc_buffer_init(&buffer, bufmem, initial_buffer_length);
1911 
1912 	result = dns_db_allrdatasets(db, node, version, now, &rdsiter);
1913 	if (result != ISC_R_SUCCESS)
1914 		goto failure;
1915 	result = dump_rdatasets_text(mctx, name, rdsiter, &ctx, &buffer, f);
1916 	if (result != ISC_R_SUCCESS)
1917 		goto failure;
1918 	dns_rdatasetiter_destroy(&rdsiter);
1919 
1920 	result = ISC_R_SUCCESS;
1921 
1922  failure:
1923 	isc_mem_put(mctx, buffer.base, buffer.length);
1924 	return (result);
1925 }
1926 
1927 isc_result_t
1928 dns_master_dumpnode(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
1929 		    dns_dbnode_t *node, dns_name_t *name,
1930 		    const dns_master_style_t *style, const char *filename)
1931 {
1932 	FILE *f = NULL;
1933 	isc_result_t result;
1934 
1935 	result = isc_stdio_open(filename, "w", &f);
1936 	if (result != ISC_R_SUCCESS) {
1937 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1938 			      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1939 			      "dumping node to file: %s: open: %s", filename,
1940 			      isc_result_totext(result));
1941 		return (ISC_R_UNEXPECTED);
1942 	}
1943 
1944 	result = dns_master_dumpnodetostream(mctx, db, version, node, name,
1945 					     style, f);
1946 	if (result != ISC_R_SUCCESS) {
1947 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1948 			      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1949 			      "dumping master file: %s: dump: %s", filename,
1950 			      isc_result_totext(result));
1951 		(void)isc_stdio_close(f);
1952 		return (ISC_R_UNEXPECTED);
1953 	}
1954 
1955 	result = isc_stdio_close(f);
1956 	if (result != ISC_R_SUCCESS) {
1957 		isc_log_write(dns_lctx, ISC_LOGCATEGORY_GENERAL,
1958 			      DNS_LOGMODULE_MASTERDUMP, ISC_LOG_ERROR,
1959 			      "dumping master file: %s: close: %s", filename,
1960 			      isc_result_totext(result));
1961 		return (ISC_R_UNEXPECTED);
1962 	}
1963 
1964 	return (result);
1965 }
1966 
1967 isc_result_t
1968 dns_master_stylecreate(dns_master_style_t **stylep, unsigned int flags,
1969 		       unsigned int ttl_column, unsigned int class_column,
1970 		       unsigned int type_column, unsigned int rdata_column,
1971 		       unsigned int line_length, unsigned int tab_width,
1972 		       isc_mem_t *mctx)
1973 {
1974 	return (dns_master_stylecreate2(stylep, flags, ttl_column,
1975 					class_column, type_column,
1976 					rdata_column, line_length,
1977 					tab_width, 0xffffffff, mctx));
1978 }
1979 
1980 isc_result_t
1981 dns_master_stylecreate2(dns_master_style_t **stylep, unsigned int flags,
1982 			unsigned int ttl_column, unsigned int class_column,
1983 			unsigned int type_column, unsigned int rdata_column,
1984 			unsigned int line_length, unsigned int tab_width,
1985 			unsigned int split_width, isc_mem_t *mctx)
1986 {
1987 	dns_master_style_t *style;
1988 
1989 	REQUIRE(stylep != NULL && *stylep == NULL);
1990 	style = isc_mem_get(mctx, sizeof(*style));
1991 	if (style == NULL)
1992 		return (ISC_R_NOMEMORY);
1993 
1994 	style->flags = flags;
1995 	style->ttl_column = ttl_column;
1996 	style->class_column = class_column;
1997 	style->type_column = type_column;
1998 	style->rdata_column = rdata_column;
1999 	style->line_length = line_length;
2000 	style->tab_width = tab_width;
2001 	style->split_width = split_width;
2002 
2003 	*stylep = style;
2004 	return (ISC_R_SUCCESS);
2005 }
2006 
2007 void
2008 dns_master_styledestroy(dns_master_style_t **stylep, isc_mem_t *mctx) {
2009 	dns_master_style_t *style;
2010 
2011 	REQUIRE(stylep != NULL && *stylep != NULL);
2012 	style = *stylep;
2013 	*stylep = NULL;
2014 	isc_mem_put(mctx, style, sizeof(*style));
2015 }
2016