+static int regdb_upgrade_v2_to_v3_fn(struct db_record *rec, void *private_data)
+{
+ const char *keyname;
+ fstring subkeyname;
+ NTSTATUS status;
+ WERROR werr;
+ uint8_t *buf;
+ uint32_t buflen, len;
+ uint32_t num_items;
+ uint32_t i;
+
+ if (rec->key.dptr == NULL || rec->key.dsize == 0) {
+ return 0;
+ }
+
+ keyname = (const char *)rec->key.dptr;
+
+ if (strncmp(keyname, REG_SORTED_SUBKEYS_PREFIX,
+ strlen(REG_SORTED_SUBKEYS_PREFIX)) == 0)
+ {
+ /* Delete the deprecated sorted subkeys cache. */
+ status = rec->delete_rec(rec);
+ if (!NT_STATUS_IS_OK(status)) {
+ DEBUG(0, ("regdb_upgrade_v2_to_v3: tdb_delete for [%s] "
+ "failed!\n", keyname));
+ return 1;
+ }
+
+ return 0;
+ }
+
+ if (strncmp(keyname, REG_VALUE_PREFIX, strlen(REG_VALUE_PREFIX)) == 0) {
+ return 0;
+ }
+
+ if (strncmp(keyname, REG_SECDESC_PREFIX,
+ strlen(REG_SECDESC_PREFIX)) == 0)
+ {
+ return 0;
+ }
+
+ /*
+ * Found a regular subkey list record.
+ * Walk the list and create the list record for those
+ * subkeys that don't already have one.
+ */
+ buf = rec->value.dptr;
+ buflen = rec->value.dsize;
+
+ len = tdb_unpack(buf, buflen, "d", &num_items);
+ if (len == (uint32_t)-1) {
+ /* invalid or empty - skip */
+ return 0;
+ }
+
+ for (i=0; i<num_items; i++) {
+ len += tdb_unpack(buf+len, buflen-len, "f", subkeyname);
+ werr = regdb_store_subkey_list(regdb, keyname, subkeyname);
+ if (!W_ERROR_IS_OK(werr)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static WERROR regdb_upgrade_v2_to_v3(struct db_context *db)
+{
+ int rc;
+ WERROR werr;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ rc = regdb->traverse(db, regdb_upgrade_v2_to_v3_fn, frame);
+ if (rc < 0) {
+ werr = WERR_REG_IO_FAILURE;
+ goto done;
+ }
+
+ werr = regdb_store_regdb_version(db, REGVER_V3);
+
+done:
+ talloc_free(frame);
+ return werr;
+}
+