}
}
-
static void
getownercase(dns_rdataset_t *rdataset, dns_name_t *name) {
if (dns_rdataset_isassociated(rdataset)) {
}
}
+static isc_result_t
+update_rdataset(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name,
+ dns_rdataset_t *rds, dns_diffop_t op) {
+ isc_result_t result;
+ unsigned int options;
+ dns_rdataset_t ardataset;
+ dns_dbnode_t *node = NULL;
+ bool is_resign;
+
+ dns_rdataset_init(&ardataset);
+
+ is_resign = rds->type == dns_rdatatype_rrsig &&
+ (op == DNS_DIFFOP_DELRESIGN || op == DNS_DIFFOP_ADDRESIGN);
+
+ if (rds->type != dns_rdatatype_nsec3 &&
+ rds->covers != dns_rdatatype_nsec3)
+ {
+ CHECK(dns_db_findnode(db, name, true, &node));
+ } else {
+ CHECK(dns_db_findnsec3node(db, name, true, &node));
+ }
+
+ switch (op) {
+ case DNS_DIFFOP_ADD:
+ case DNS_DIFFOP_ADDRESIGN:
+ options = DNS_DBADD_MERGE | DNS_DBADD_EXACT |
+ DNS_DBADD_EXACTTTL;
+ CHECK(dns_db_addrdataset(db, node, ver, 0, rds, options,
+ &ardataset));
+ break;
+ case DNS_DIFFOP_DEL:
+ case DNS_DIFFOP_DELRESIGN:
+ options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD;
+ result = dns_db_subtractrdataset(db, node, ver, rds, options,
+ &ardataset);
+ switch (result) {
+ case ISC_R_SUCCESS:
+ case DNS_R_UNCHANGED:
+ case DNS_R_NXRRSET:
+ getownercase(&ardataset, name);
+ CHECK(result);
+ break;
+ default:
+ CHECK(result);
+ break;
+ }
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ if (is_resign) {
+ isc_stdtime_t resign;
+ resign = dns_rdataset_minresign(&ardataset);
+ dns_db_setsigningtime(db, &ardataset, resign);
+ }
+
+cleanup:
+ if (node != NULL) {
+ dns_db_detachnode(&node);
+ }
+ if (dns_rdataset_isassociated(&ardataset)) {
+ dns_rdataset_disassociate(&ardataset);
+ }
+ return result;
+}
+
+static isc_result_t
+update_callback(void *arg, const dns_name_t *name, dns_rdataset_t *rds,
+ dns_diffop_t op DNS__DB_FLARG) {
+ dns_updatectx_t *ctx = arg;
+ return update_rdataset(ctx->db, ctx->ver, (dns_name_t *)name, rds, op);
+}
+
static const char *
optotext(dns_diffop_t op) {
switch (op) {
}
static isc_result_t
-diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver,
- bool warn) {
+diff_apply(const dns_diff_t *diff, dns_rdatacallbacks_t *callbacks) {
dns_difftuple_t *t;
- dns_dbnode_t *node = NULL;
isc_result_t result;
char namebuf[DNS_NAME_FORMATSIZE];
char typebuf[DNS_RDATATYPE_FORMATSIZE];
char classbuf[DNS_RDATACLASS_FORMATSIZE];
+ dns_updatectx_t *ctx;
REQUIRE(DNS_DIFF_VALID(diff));
- REQUIRE(DNS_DB_VALID(db));
+ REQUIRE(callbacks != NULL);
+ REQUIRE(callbacks->update != NULL);
+
+ ctx = callbacks->add_private;
t = ISC_LIST_HEAD(diff->tuples);
while (t != NULL) {
dns_name_t *name;
- INSIST(node == NULL);
name = &t->name;
/*
* Find the node.
dns_diffop_t op;
dns_rdatalist_t rdl;
dns_rdataset_t rds;
- dns_rdataset_t ardataset;
- unsigned int options;
op = t->op;
type = t->rdata.type;
rdl.rdclass = t->rdata.rdclass;
rdl.ttl = t->ttl;
- node = NULL;
- if (type != dns_rdatatype_nsec3 &&
- covers != dns_rdatatype_nsec3)
- {
- CHECK(dns_db_findnode(db, name, true, &node));
- } else {
- CHECK(dns_db_findnsec3node(db, name, true,
- &node));
- }
-
while (t != NULL && dns_name_equal(&t->name, name) &&
t->op == op && t->rdata.type == type &&
rdata_covers(&t->rdata) == covers)
* dns_rdataset_setownercase.
*/
name = &t->name;
- if (t->ttl != rdl.ttl && warn) {
+ if (t->ttl != rdl.ttl && ctx->warn) {
dns_name_format(name, namebuf,
sizeof(namebuf));
dns_rdatatype_format(t->rdata.type,
* Convert the rdatalist into a rdataset.
*/
dns_rdataset_init(&rds);
- dns_rdataset_init(&ardataset);
dns_rdatalist_tordataset(&rdl, &rds);
dns_rdataset_setownercase(&rds, name);
rds.trust = dns_trust_ultimate;
/*
* Merge the rdataset into the database.
*/
- switch (op) {
- case DNS_DIFFOP_ADD:
- case DNS_DIFFOP_ADDRESIGN:
- options = DNS_DBADD_MERGE | DNS_DBADD_EXACT |
- DNS_DBADD_EXACTTTL;
- result = dns_db_addrdataset(db, node, ver, 0,
- &rds, options,
- &ardataset);
- break;
- case DNS_DIFFOP_DEL:
- case DNS_DIFFOP_DELRESIGN:
- options = DNS_DBSUB_EXACT | DNS_DBSUB_WANTOLD;
- result = dns_db_subtractrdataset(db, node, ver,
- &rds, options,
- &ardataset);
- break;
- default:
- UNREACHABLE();
- }
+ result = callbacks->update(callbacks->add_private, name,
+ &rds, op DNS__DB_FILELINE);
- if (result == ISC_R_SUCCESS) {
- if (rds.type == dns_rdatatype_rrsig &&
- (op == DNS_DIFFOP_DELRESIGN ||
- op == DNS_DIFFOP_ADDRESIGN))
- {
- isc_stdtime_t resign;
- resign = dns_rdataset_minresign(&ardataset);
- dns_db_setsigningtime(db, &ardataset,
- resign);
- }
- if (op == DNS_DIFFOP_DEL ||
- op == DNS_DIFFOP_DELRESIGN)
- {
- getownercase(&ardataset, name);
- }
- } else if (result == DNS_R_UNCHANGED) {
+ switch (result) {
+ case ISC_R_SUCCESS:
+ /*
+ * OK.
+ */
+ break;
+ case DNS_R_UNCHANGED:
/*
* This will not happen when executing a
* dynamic update, because that code will
* from a server that is not as careful.
* Issue a warning and continue.
*/
- if (warn) {
- dns_name_format(dns_db_origin(db),
+ if (ctx->warn) {
+ dns_name_format(dns_db_origin(ctx->db),
namebuf,
sizeof(namebuf));
- dns_rdataclass_format(dns_db_class(db),
- classbuf,
- sizeof(classbuf));
+ dns_rdataclass_format(
+ dns_db_class(ctx->db), classbuf,
+ sizeof(classbuf));
isc_log_write(DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DIFF,
ISC_LOG_WARNING,
"update with no effect",
namebuf, classbuf);
}
- if (op == DNS_DIFFOP_DEL ||
- op == DNS_DIFFOP_DELRESIGN)
- {
- getownercase(&ardataset, name);
- }
- } else if (result == DNS_R_NXRRSET) {
+ result = ISC_R_SUCCESS;
+ break;
+ case DNS_R_NXRRSET:
/*
* OK.
*/
- if (op == DNS_DIFFOP_DEL ||
- op == DNS_DIFFOP_DELRESIGN)
- {
- getownercase(&ardataset, name);
- }
- if (dns_rdataset_isassociated(&ardataset)) {
- dns_rdataset_disassociate(&ardataset);
- }
- } else {
- if (result == DNS_R_NOTEXACT) {
- dns_name_format(name, namebuf,
- sizeof(namebuf));
- dns_rdatatype_format(type, typebuf,
- sizeof(typebuf));
- dns_rdataclass_format(rdclass, classbuf,
- sizeof(classbuf));
- isc_log_write(
- DNS_LOGCATEGORY_GENERAL,
- DNS_LOGMODULE_DIFF,
- ISC_LOG_ERROR,
- "dns_diff_apply: %s/%s/%s: %s "
- "%s",
- namebuf, typebuf, classbuf,
- optotext(op),
- isc_result_totext(result));
- }
- if (dns_rdataset_isassociated(&ardataset)) {
- dns_rdataset_disassociate(&ardataset);
- }
- CHECK(result);
- }
- dns_db_detachnode(&node);
- if (dns_rdataset_isassociated(&ardataset)) {
- dns_rdataset_disassociate(&ardataset);
+ result = ISC_R_SUCCESS;
+ break;
+ case DNS_R_NOTEXACT:
+ dns_name_format(name, namebuf, sizeof(namebuf));
+ dns_rdatatype_format(type, typebuf,
+ sizeof(typebuf));
+ dns_rdataclass_format(rdclass, classbuf,
+ sizeof(classbuf));
+ isc_log_write(DNS_LOGCATEGORY_GENERAL,
+ DNS_LOGMODULE_DIFF, ISC_LOG_ERROR,
+ "dns_diff_apply: %s/%s/%s: %s "
+ "%s",
+ namebuf, typebuf, classbuf,
+ optotext(op),
+ isc_result_totext(result));
+ break;
+ default:
+ break;
}
+
+ CHECK(result);
}
}
return ISC_R_SUCCESS;
cleanup:
- if (node != NULL) {
- dns_db_detachnode(&node);
- }
return result;
}
isc_result_t
dns_diff_apply(const dns_diff_t *diff, dns_db_t *db, dns_dbversion_t *ver) {
- return diff_apply(diff, db, ver, true);
+ dns_updatectx_t ctx = { .db = db, .ver = ver, .warn = true };
+ dns_rdatacallbacks_t callbacks;
+ dns_rdatacallbacks_init(&callbacks);
+ callbacks.update = update_callback;
+ callbacks.add_private = &ctx;
+ return diff_apply(diff, &callbacks);
}
isc_result_t
dns_diff_applysilently(const dns_diff_t *diff, dns_db_t *db,
dns_dbversion_t *ver) {
- return diff_apply(diff, db, ver, false);
+ dns_updatectx_t ctx = { .db = db, .ver = ver, .warn = false };
+ dns_rdatacallbacks_t callbacks;
+ dns_rdatacallbacks_init(&callbacks);
+ callbacks.update = update_callback;
+ callbacks.add_private = &ctx;
+ return diff_apply(diff, &callbacks);
+}
+
+isc_result_t
+dns_diff_apply_with_callbacks(const dns_diff_t *diff,
+ dns_rdatacallbacks_t *callbacks) {
+ REQUIRE(DNS_DIFF_VALID(diff));
+ REQUIRE(callbacks != NULL);
+ REQUIRE(callbacks->update != NULL);
+
+ return diff_apply(diff, callbacks);
}
/* XXX this duplicates lots of code in diff_apply(). */
rds.trust = dns_trust_ultimate;
INSIST(op == DNS_DIFFOP_ADD);
- result = callbacks->add(callbacks->add_private, name,
- &rds DNS__DB_FILELINE);
+ result = callbacks->update(
+ callbacks->add_private, name, &rds,
+ DNS_DIFFOP_ADD DNS__DB_FILELINE);
if (result == DNS_R_UNCHANGED) {
isc_log_write(DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_DIFF,
isc_result_t (*beginload)(dns_db_t *db,
dns_rdatacallbacks_t *callbacks);
isc_result_t (*endload)(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
+ isc_result_t (*beginupdate)(dns_db_t *db,
+ dns_rdatacallbacks_t *callbacks);
+ isc_result_t (*commitupdate)(dns_db_t *db,
+ dns_rdatacallbacks_t *callbacks);
+ isc_result_t (*abortupdate)(dns_db_t *db,
+ dns_rdatacallbacks_t *callbacks);
void (*currentversion)(dns_db_t *db, dns_dbversion_t **versionp);
isc_result_t (*newversion)(dns_db_t *db, dns_dbversion_t **versionp);
void (*attachversion)(dns_db_t *db, dns_dbversion_t *source,
* implementation used, syntax errors in the master file, etc.
*/
+isc_result_t
+dns_db_beginupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
+/*%<
+ * Begin updating 'db'.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database.
+ *
+ * \li 'callbacks' is a pointer to an initialized dns_rdatacallbacks_t
+ * structure.
+ *
+ * Ensures:
+ *
+ * \li On success, callbacks->add will be a valid dns_addrdatasetfunc_t
+ * suitable for updating records in 'db' from IXFR operations.
+ * callbacks->add_private will be a valid DB update context
+ * which should be used as 'arg' when callbacks->add is called.
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_commitupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
+/*%<
+ * Commit the update to 'db'. Must be safe to double-call or call after
+ * dns_db_abortupdate.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database that is being updated.
+ *
+ * \li 'callbacks' is a valid dns_rdatacallbacks_t structure.
+ *
+ * \li callbacks->add_private is not NULL and is a valid database update context.
+ *
+ * Ensures:
+ *
+ * \li 'callbacks' is returned to its state prior to calling dns_db_beginupdate()
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
+isc_result_t
+dns_db_abortupdate(dns_db_t *db, dns_rdatacallbacks_t *callbacks);
+/*%<
+ * Abort the update to 'db'. Must be safe to double-call or call after
+ * dns_db_commitupdate.
+ *
+ * Requires:
+ *
+ * \li 'db' is a valid database that is being updated.
+ *
+ * \li 'callbacks' is a valid dns_rdatacallbacks_t structure.
+ *
+ * \li callbacks->add_private is not NULL and is a valid database update context.
+ *
+ * Ensures:
+ *
+ * \li 'callbacks' is returned to its state prior to calling dns_db_beginupdate()
+ *
+ * Returns:
+ *
+ * \li #ISC_R_SUCCESS
+ *
+ * \li Other results are possible, depending upon the database
+ * implementation used.
+ */
+
isc_result_t
dns_db_load(dns_db_t *db, const char *filename, dns_masterformat_t format,
unsigned int options);