From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by olra.theworths.org (Postfix) with ESMTP id AEFF1431FD0 for ; Sun, 28 Sep 2014 11:29:13 -0700 (PDT) X-Virus-Scanned: Debian amavisd-new at olra.theworths.org X-Spam-Flag: NO X-Spam-Score: 0 X-Spam-Level: X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none] autolearn=disabled Received: from olra.theworths.org ([127.0.0.1]) by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id vttyfHCfwrR7 for ; Sun, 28 Sep 2014 11:29:08 -0700 (PDT) Received: from yantan.tethera.net (yantan.tethera.net [199.188.72.155]) (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits)) (No client certificate requested) by olra.theworths.org (Postfix) with ESMTPS id 7F2FE431FD2 for ; Sun, 28 Sep 2014 11:29:01 -0700 (PDT) Received: from remotemail by yantan.tethera.net with local (Exim 4.80) (envelope-from ) id 1XYJDR-0005gE-6N; Sun, 28 Sep 2014 15:29:01 -0300 Received: (nullmailer pid 31290 invoked by uid 1000); Sun, 28 Sep 2014 18:28:49 -0000 From: David Bremner To: notmuch@notmuchmail.org Subject: [WIP 3/3] lib: add configuration framework. Date: Sun, 28 Sep 2014 20:28:19 +0200 Message-Id: <1411928899-29625-4-git-send-email-david@tethera.net> X-Mailer: git-send-email 2.1.0 In-Reply-To: <1411928899-29625-1-git-send-email-david@tethera.net> References: <87iok8vog6.fsf@steelpick.2x.cz> <1411928899-29625-1-git-send-email-david@tethera.net> X-BeenThere: notmuch@notmuchmail.org X-Mailman-Version: 2.1.13 Precedence: list List-Id: "Use and development of the notmuch mail system." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 28 Sep 2014 18:29:14 -0000 Allow clients to atomically get and set key value pairs. --- lib/Makefile.local | 1 + lib/config.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/notmuch.h | 7 +++ test/Makefile.local | 7 +++ test/T560-lib-config.sh | 15 +++++ test/config-test.c | 28 +++++++++ 6 files changed, 214 insertions(+) create mode 100644 lib/config.c create mode 100755 test/T560-lib-config.sh create mode 100644 test/config-test.c diff --git a/lib/Makefile.local b/lib/Makefile.local index 4120390..7ca2b3b 100644 --- a/lib/Makefile.local +++ b/lib/Makefile.local @@ -54,6 +54,7 @@ lib := $(dir) libnotmuch_c_srcs = \ $(notmuch_compat_srcs) \ + $(dir)/config.c \ $(dir)/filenames.c \ $(dir)/string-list.c \ $(dir)/libsha1.c \ diff --git a/lib/config.c b/lib/config.c new file mode 100644 index 0000000..c3b8f39 --- /dev/null +++ b/lib/config.c @@ -0,0 +1,156 @@ +#include "notmuch-private.h" +#include "string-util.h" +#include "file-util.h" +#include + +static notmuch_status_t +compute_paths (void *ctx, const char *notmuch_path, const char *key, + char **parent_out, char **dest_out) { + + char *parent, *dest, *final_component, *last_slash; + + parent = talloc_asprintf (ctx, "%s/config/%s", notmuch_path, key); + if (!parent) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + + last_slash = strrchr (parent, '/'); + *last_slash = '\0'; + + final_component = talloc_strdup (ctx, last_slash + 1); + + dest = talloc_asprintf(ctx, "%s/_%s", parent, final_component); + if (!dest) + return NOTMUCH_STATUS_OUT_OF_MEMORY; + + *parent_out = parent; + *dest_out = dest; + + return NOTMUCH_STATUS_SUCCESS; + +} + +notmuch_status_t +notmuch_config_get (const char *notmuch_path, const char *key, const char **val){ + + char *line = NULL; + size_t line_size; + ssize_t line_len; + char *buf = NULL; + char *file_name, *parent; + notmuch_status_t status; + void *local = NULL; + FILE *file_ptr = NULL; + + if (notmuch_path == NULL || key == NULL || val == NULL) + return NOTMUCH_STATUS_NULL_POINTER; + + local = talloc_new (NULL); + + status = compute_paths (local, notmuch_path, key, &parent, &file_name); + if (status) + goto DONE; + + file_ptr = fopen (file_name, "r"); + if (file_ptr == NULL) { + status = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + while ((line_len = getline (&line, &line_size, file_ptr)) != -1) { + + if (buf) + buf = talloc_asprintf (local, "%s%s", buf, line); + else + buf = talloc_strdup (local, line); + + if (buf == NULL) { + status = NOTMUCH_STATUS_OUT_OF_MEMORY; + goto DONE; + } + + } + + + /* remove the last newline. Convenient for the single line case. */ + chomp_newline (buf); + + *val = buf; + status = NOTMUCH_STATUS_SUCCESS; + + DONE: + if (line) + free (line); + + if (file_ptr) + fclose (file_ptr); + + talloc_free (local); + + return status; +} + +notmuch_status_t +notmuch_config_set (const char *notmuch_path, const char *key, const char *val){ + + char *parent, *path, *temp_path; + int out_fd = -1; + notmuch_status_t status = NOTMUCH_STATUS_SUCCESS; + void *local = NULL; + FILE *out_file; + + if (notmuch_path == NULL || key == NULL || val == NULL) + return NOTMUCH_STATUS_NULL_POINTER; + + if (has_double_dot_component (key)) + return NOTMUCH_STATUS_UNSUPPORTED_OPERATION; + + local = talloc_new (NULL); + + status = compute_paths (local, notmuch_path, key, &parent, &path); + if (status) + goto DONE; + + if (! mkdir_recursive (local, parent, 0700)) { + status = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + temp_path = talloc_asprintf (local, "%s/tmp.XXXXXX", parent); + if (temp_path == NULL) { + status = NOTMUCH_STATUS_OUT_OF_MEMORY; + goto DONE; + } + + out_fd = mkstemp (temp_path); + if (out_fd == -1) { + status = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + out_file = fdopen (out_fd, "w"); + if (out_file == NULL) { + status = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + if (fputs (val, out_file) == EOF) { + status = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + if (fclose (out_file)) { + status = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + if (rename (temp_path, path) < 0) { + status = NOTMUCH_STATUS_FILE_ERROR; + goto DONE; + } + + DONE: + + talloc_free(local); + + return status; +} diff --git a/lib/notmuch.h b/lib/notmuch.h index fe2340b..9a5f9df 100644 --- a/lib/notmuch.h +++ b/lib/notmuch.h @@ -192,6 +192,13 @@ typedef struct _notmuch_directory notmuch_directory_t; typedef struct _notmuch_filenames notmuch_filenames_t; #endif /* __DOXYGEN__ */ + +notmuch_status_t +notmuch_config_get (const char *notmuch_path, const char *key, const char **val); + +notmuch_status_t +notmuch_config_set (const char *notmuch_path, const char *key, const char *val); + /** * Create a new, empty notmuch database located at 'path'. * diff --git a/test/Makefile.local b/test/Makefile.local index a2d58fc..8a203f0 100644 --- a/test/Makefile.local +++ b/test/Makefile.local @@ -23,6 +23,9 @@ random_corpus_deps = $(dir)/random-corpus.o $(dir)/database-test.o \ lib/libnotmuch.a util/libutil.a \ parse-time-string/libparse-time-string.a +config_test_deps = $(dir)/config-test.o \ + lib/libnotmuch.a util/libutil.a + $(dir)/random-corpus: $(random_corpus_deps) $(call quiet,CXX) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS) @@ -38,6 +41,9 @@ $(dir)/parse-time: $(dir)/parse-time.o parse-time-string/parse-time-string.o $(dir)/make-db-version: $(dir)/make-db-version.o $(call quiet,CXX) $^ -o $@ $(XAPIAN_LDFLAGS) +$(dir)/config-test: $(config_test_deps) + $(call quiet,CXX) $(CFLAGS_FINAL) $^ -o $@ $(CONFIGURE_LDFLAGS) + .PHONY: test check test_main_srcs=$(dir)/arg-test.c \ @@ -47,6 +53,7 @@ test_main_srcs=$(dir)/arg-test.c \ $(dir)/smtp-dummy.c \ $(dir)/symbol-test.cc \ $(dir)/make-db-version.cc \ + $(dir)/config-test.c \ test_srcs=$(test_main_srcs) $(dir)/database-test.c diff --git a/test/T560-lib-config.sh b/test/T560-lib-config.sh new file mode 100755 index 0000000..ec8ddbe --- /dev/null +++ b/test/T560-lib-config.sh @@ -0,0 +1,15 @@ +#!/usr/bin/env bash +test_description="library config handling" + +. ./test-lib.sh + +test_begin_subtest "getting and setting" +${TEST_DIRECTORY}/config-test ${MAIL_DIR}/.notmuch set a foo +${TEST_DIRECTORY}/config-test ${MAIL_DIR}/.notmuch set a/b bar +${TEST_DIRECTORY}/config-test ${MAIL_DIR}/.notmuch set b/a fub +${TEST_DIRECTORY}/config-test ${MAIL_DIR}/.notmuch get a >> OUTPUT +${TEST_DIRECTORY}/config-test ${MAIL_DIR}/.notmuch get a/b >> OUTPUT +${TEST_DIRECTORY}/config-test ${MAIL_DIR}/.notmuch get b/a >> OUTPUT +test_expect_equal "$(cat OUTPUT)" "foobarfub" + +test_done diff --git a/test/config-test.c b/test/config-test.c new file mode 100644 index 0000000..d9a1116 --- /dev/null +++ b/test/config-test.c @@ -0,0 +1,28 @@ +#include +#include + +#include "notmuch.h" + +int +main (int argc, char **argv) { + const char *val; + notmuch_status_t status; + + if (argc == 4 && strcmp (argv[2], "get") == 0) { + + status = notmuch_config_get (argv[1], argv[3], &val); + if (status) + return status; + fputs (val, stdout); + return 0; + + } else if (argc == 5 && strcmp (argv[2], "set") == 0) { + + status = notmuch_config_set (argv[1], argv[3], argv[4]); + if (status) + return status; + return 0; + } + + return 1; +} -- 2.1.0