Commit 271e5fbafd0218c121646be30b4c780224eb1f8b

Patrick Steinhardt 2019-07-24T18:18:18

config_file: duplicate accessors for readonly backend While most functions of the readonly configuration backend are implemented separately from the writeable configuration backend, the two functions `config_iterator_new` and `config_get` are shared between both. This sharing makes it necessary to have some shared data structures, which is the `diskfile_header` structure. Unfortunately, this makes the backends harder to grasp than necessary due to all the casting between structs and also quite error prone. Reimplement those functions for the readonly backends. As readonly backends cannot be refreshed anyway, we can remove the calls to `config_refresh` in there.

diff --git a/src/config_file.c b/src/config_file.c
index 72f75c8..3a80244 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -284,6 +284,25 @@ out:
 	return error;
 }
 
+static int config_iterator_new_readonly(
+	git_config_iterator **iter,
+	struct git_config_backend *backend)
+{
+	diskfile_header *bh = GIT_CONTAINER_OF(backend, diskfile_header, parent);
+	git_config_entries *entries = NULL;
+	int error;
+
+	if ((error = git_config_entries_dup(&entries, bh->entries)) < 0 ||
+	    (error = git_config_entries_iterator_new(iter, entries)) < 0)
+		goto out;
+
+out:
+	/* Let iterator delete duplicated entries when it's done */
+	git_config_entries_free(entries);
+	return error;
+}
+
+
 static int config_set(git_config_backend *cfg, const char *name, const char *value)
 {
 	diskfile_backend *b = GIT_CONTAINER_OF(cfg, diskfile_backend, header.parent);
@@ -361,6 +380,28 @@ static int config_get(git_config_backend *cfg, const char *key, git_config_entry
 	return 0;
 }
 
+static int config_get_readonly(git_config_backend *cfg, const char *key, git_config_entry **out)
+{
+	diskfile_header *h = GIT_CONTAINER_OF(cfg, diskfile_header, parent);
+	git_config_entries *entries = NULL;
+	git_config_entry *entry;
+	int error = 0;
+
+	if ((entries = diskfile_entries_take(h)) == NULL)
+		return -1;
+
+	if ((error = (git_config_entries_get(&entry, entries, key))) < 0) {
+		git_config_entries_free(entries);
+		return error;
+	}
+
+	entry->free = free_diskfile_entry;
+	entry->payload = entries;
+	*out = entry;
+
+	return 0;
+}
+
 static int config_set_multivar(
 	git_config_backend *cfg, const char *name, const char *regexp, const char *value)
 {
@@ -642,12 +683,12 @@ static int config_snapshot(git_config_backend **out, git_config_backend *source)
 	backend->header.parent.readonly = 1;
 	backend->header.parent.version = GIT_CONFIG_BACKEND_VERSION;
 	backend->header.parent.open = config_readonly_open;
-	backend->header.parent.get = config_get;
+	backend->header.parent.get = config_get_readonly;
 	backend->header.parent.set = config_set_readonly;
 	backend->header.parent.set_multivar = config_set_multivar_readonly;
 	backend->header.parent.del = config_delete_readonly;
 	backend->header.parent.del_multivar = config_delete_multivar_readonly;
-	backend->header.parent.iterator = config_iterator_new;
+	backend->header.parent.iterator = config_iterator_new_readonly;
 	backend->header.parent.lock = config_lock_readonly;
 	backend->header.parent.unlock = config_unlock_readonly;
 	backend->header.parent.free = backend_readonly_free;