X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-dump.c;h=2849eabaadb9b292b0eab8e4dab6c10d4b26398d;hp=179e2e97bf61e964b9a9b63b7939b4d805b8f103;hb=3c13bc0321baaf340663779d6fce2b1f34c1c2c3;hpb=2a79d81211664ca3f0cd1a847795d48bd66b8a3d diff --git a/notmuch-dump.c b/notmuch-dump.c index 179e2e97..2849eaba 100644 --- a/notmuch-dump.c +++ b/notmuch-dump.c @@ -19,11 +19,13 @@ */ #include "notmuch-client.h" -#include "dump-restore-private.h" +#include "hex-escape.h" #include "string-util.h" +#include + static int -database_dump_file (notmuch_database_t *notmuch, FILE *output, +database_dump_file (notmuch_database_t *notmuch, gzFile output, const char *query_str, int output_format) { notmuch_query_t *query; @@ -69,7 +71,7 @@ database_dump_file (notmuch_database_t *notmuch, FILE *output, } if (output_format == DUMP_FORMAT_SUP) { - fprintf (output, "%s (", message_id); + gzprintf (output, "%s (", message_id); } for (tags = notmuch_message_get_tags (message); @@ -78,12 +80,12 @@ database_dump_file (notmuch_database_t *notmuch, FILE *output, const char *tag_str = notmuch_tags_get (tags); if (! first) - fputs (" ", output); + gzputs (output, " "); first = 0; if (output_format == DUMP_FORMAT_SUP) { - fputs (tag_str, output); + gzputs (output, tag_str); } else { if (hex_encode (notmuch, tag_str, &buffer, &buffer_size) != HEX_SUCCESS) { @@ -91,12 +93,12 @@ database_dump_file (notmuch_database_t *notmuch, FILE *output, tag_str); return EXIT_FAILURE; } - fprintf (output, "+%s", buffer); + gzprintf (output, "+%s", buffer); } } if (output_format == DUMP_FORMAT_SUP) { - fputs (")\n", output); + gzputs (output, ")\n"); } else { if (make_boolean_term (notmuch, "id", message_id, &buffer, &buffer_size)) { @@ -104,7 +106,7 @@ database_dump_file (notmuch_database_t *notmuch, FILE *output, message_id, strerror (errno)); return EXIT_FAILURE; } - fprintf (output, " -- %s\n", buffer); + gzprintf (output, " -- %s\n", buffer); } notmuch_message_destroy (message); @@ -115,11 +117,97 @@ database_dump_file (notmuch_database_t *notmuch, FILE *output, return EXIT_SUCCESS; } +/* Dump database into output_file_name if it's non-NULL, stdout + * otherwise. + */ +int +notmuch_database_dump (notmuch_database_t *notmuch, + const char *output_file_name, + const char *query_str, + dump_format_t output_format, + notmuch_bool_t gzip_output) +{ + gzFile output = NULL; + const char *mode = gzip_output ? "w9" : "wT"; + const char *name_for_error = output_file_name ? output_file_name : "stdout"; + + char *tempname = NULL; + int outfd = -1; + + int ret = -1; + + if (output_file_name) { + tempname = talloc_asprintf (notmuch, "%s.XXXXXX", output_file_name); + outfd = mkstemp (tempname); + } else { + outfd = dup (STDOUT_FILENO); + } + + if (outfd < 0) { + fprintf (stderr, "Bad output file %s\n", name_for_error); + goto DONE; + } + + output = gzdopen (outfd, mode); + + if (output == NULL) { + fprintf (stderr, "Error opening %s for (gzip) writing: %s\n", + name_for_error, strerror (errno)); + if (close (outfd)) + fprintf (stderr, "Error closing %s during shutdown: %s\n", + name_for_error, strerror (errno)); + goto DONE; + } + + ret = database_dump_file (notmuch, output, query_str, output_format); + if (ret) goto DONE; + + ret = gzflush (output, Z_FINISH); + if (ret) { + fprintf (stderr, "Error flushing output: %s\n", gzerror (output, NULL)); + goto DONE; + } + + if (output_file_name) { + ret = fdatasync (outfd); + if (ret) { + fprintf (stderr, "Error syncing %s to disk: %s\n", + name_for_error, strerror (errno)); + goto DONE; + } + } + + if (gzclose_w (output) != Z_OK) { + fprintf (stderr, "Error closing %s: %s\n", name_for_error, + gzerror (output, NULL)); + ret = EXIT_FAILURE; + output = NULL; + goto DONE; + } + + if (output_file_name) { + ret = rename (tempname, output_file_name); + if (ret) { + fprintf (stderr, "Error renaming %s to %s: %s\n", + tempname, output_file_name, strerror (errno)); + goto DONE; + } + + } + DONE: + if (ret != EXIT_SUCCESS && output) + (void) gzclose_w (output); + + if (ret != EXIT_SUCCESS && output_file_name) + (void) unlink (tempname); + + return ret; +} + int notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[]) { notmuch_database_t *notmuch; - FILE *output = stdout; const char *query_str = NULL; int ret; @@ -131,6 +219,7 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[]) int opt_index; int output_format = DUMP_FORMAT_BATCH_TAG; + notmuch_bool_t gzip_output = 0; notmuch_opt_desc_t options[] = { { NOTMUCH_OPT_KEYWORD, &output_format, "format", 'f', @@ -138,6 +227,7 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[]) { "batch-tag", DUMP_FORMAT_BATCH_TAG }, { 0, 0 } } }, { NOTMUCH_OPT_STRING, &output_file_name, "output", 'o', 0 }, + { NOTMUCH_OPT_BOOLEAN, &gzip_output, "gzip", 'z', 0 }, { 0, 0, 0, 0, 0 } }; @@ -145,16 +235,6 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[]) if (opt_index < 0) return EXIT_FAILURE; - if (output_file_name) { - output = fopen (output_file_name, "w"); - if (output == NULL) { - fprintf (stderr, "Error opening %s for writing: %s\n", - output_file_name, strerror (errno)); - return EXIT_FAILURE; - } - } - - if (opt_index < argc) { query_str = query_string_from_args (notmuch, argc - opt_index, argv + opt_index); if (query_str == NULL) { @@ -163,10 +243,8 @@ notmuch_dump_command (notmuch_config_t *config, int argc, char *argv[]) } } - ret = database_dump_file (notmuch, output, query_str, output_format); - - if (output != stdout) - fclose (output); + ret = notmuch_database_dump (notmuch, output_file_name, query_str, + output_format, gzip_output); notmuch_database_destroy (notmuch);