+static void clean_up_db(struct userdata *u) {
+ struct clean_up_item {
+ PA_LLIST_FIELDS(struct clean_up_item);
+ char *entry_name;
+ struct entry *entry;
+ };
+
+ PA_LLIST_HEAD(struct clean_up_item, to_be_removed);
+#ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
+ PA_LLIST_HEAD(struct clean_up_item, to_be_converted);
+#endif
+ pa_bool_t done = FALSE;
+ pa_datum key;
+ struct clean_up_item *item = NULL;
+ struct clean_up_item *next = NULL;
+
+ pa_assert(u);
+
+ /* It would be convenient to remove or replace the entries in the database
+ * in the same loop that iterates through the database, but modifying the
+ * database is not supported while iterating through it. That's why we
+ * collect the entries that need to be removed or replaced to these
+ * lists. */
+ PA_LLIST_HEAD_INIT(struct clean_up_item, to_be_removed);
+#ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
+ PA_LLIST_HEAD_INIT(struct clean_up_item, to_be_converted);
+#endif
+
+ done = !pa_database_first(u->database, &key, NULL);
+ while (!done) {
+ pa_datum next_key;
+ char *entry_name = NULL;
+ struct entry *e = NULL;
+
+ entry_name = pa_xstrndup(key.data, key.size);
+
+ /* Use entry_read() to check whether this entry is valid. */
+ if (!(e = entry_read(u, entry_name))) {
+ item = pa_xnew0(struct clean_up_item, 1);
+ PA_LLIST_INIT(struct clean_up_item, item);
+ item->entry_name = entry_name;
+
+#ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
+ /* entry_read() failed, but what about legacy_entry_read()? */
+ if (!(e = legacy_entry_read(u, entry_name)))
+ /* Not a legacy entry either, let's remove this. */
+ PA_LLIST_PREPEND(struct clean_up_item, to_be_removed, item);
+ else {
+ /* Yay, it's valid after all! Now let's convert the entry to the current format. */
+ item->entry = e;
+ PA_LLIST_PREPEND(struct clean_up_item, to_be_converted, item);
+ }
+#else
+ /* Invalid entry, let's remove this. */
+ PA_LLIST_PREPEND(struct clean_up_item, to_be_removed, item);
+#endif
+ } else {
+ pa_xfree(entry_name);
+ entry_free(e);
+ }
+
+ done = !pa_database_next(u->database, &key, &next_key, NULL);
+ pa_datum_free(&key);
+ key = next_key;
+ }
+
+ PA_LLIST_FOREACH_SAFE(item, next, to_be_removed) {
+ key.data = item->entry_name;
+ key.size = strlen(item->entry_name);
+
+ pa_log_debug("Removing an invalid entry: %s", item->entry_name);
+
+ pa_assert_se(pa_database_unset(u->database, &key) >= 0);
+ trigger_save(u);
+
+ PA_LLIST_REMOVE(struct clean_up_item, to_be_removed, item);
+ pa_xfree(item->entry_name);
+ pa_xfree(item);
+ }
+
+#ifdef ENABLE_LEGACY_DATABASE_ENTRY_FORMAT
+ PA_LLIST_FOREACH_SAFE(item, next, to_be_converted) {
+ pa_log_debug("Upgrading a legacy entry to the current format: %s", item->entry_name);
+
+ pa_assert_se(entry_write(u, item->entry_name, item->entry, TRUE) >= 0);
+ trigger_save(u);
+
+ PA_LLIST_REMOVE(struct clean_up_item, to_be_converted, item);
+ pa_xfree(item->entry_name);
+ entry_free(item->entry);
+ pa_xfree(item);
+ }
+#endif
+}
+