--- /dev/null
+Return-Path: <bremner@tethera.net>\r
+X-Original-To: notmuch@notmuchmail.org\r
+Delivered-To: notmuch@notmuchmail.org\r
+Received: from localhost (localhost [127.0.0.1])\r
+ by olra.theworths.org (Postfix) with ESMTP id 3EB4B431FBD\r
+ for <notmuch@notmuchmail.org>; Tue, 1 Apr 2014 18:16:42 -0700 (PDT)\r
+X-Virus-Scanned: Debian amavisd-new at olra.theworths.org\r
+X-Spam-Flag: NO\r
+X-Spam-Score: 0\r
+X-Spam-Level: \r
+X-Spam-Status: No, score=0 tagged_above=-999 required=5 tests=[none]\r
+ autolearn=disabled\r
+Received: from olra.theworths.org ([127.0.0.1])\r
+ by localhost (olra.theworths.org [127.0.0.1]) (amavisd-new, port 10024)\r
+ with ESMTP id v5WP+BNshXoG for <notmuch@notmuchmail.org>;\r
+ Tue, 1 Apr 2014 18:16:41 -0700 (PDT)\r
+Received: from yantan.tethera.net (yantan.tethera.net [199.188.72.155])\r
+ (using TLSv1 with cipher DHE-RSA-AES128-SHA (128/128 bits))\r
+ (No client certificate requested)\r
+ by olra.theworths.org (Postfix) with ESMTPS id B06D4431FC2\r
+ for <notmuch@notmuchmail.org>; Tue, 1 Apr 2014 18:16:40 -0700 (PDT)\r
+Received: from remotemail by yantan.tethera.net with local (Exim 4.80)\r
+ (envelope-from <bremner@tethera.net>)\r
+ id 1WV9nE-00072u-Ef; Tue, 01 Apr 2014 22:16:40 -0300\r
+Received: (nullmailer pid 18501 invoked by uid 1000); Wed, 02 Apr 2014\r
+ 01:16:26 -0000\r
+From: David Bremner <david@tethera.net>\r
+To: notmuch@notmuchmail.org\r
+Subject: [Patch v5 2/6] dump: when given output file name, write atomically\r
+Date: Tue, 1 Apr 2014 22:16:17 -0300\r
+Message-Id: <1396401381-18128-3-git-send-email-david@tethera.net>\r
+X-Mailer: git-send-email 1.9.0\r
+In-Reply-To: <1396401381-18128-1-git-send-email-david@tethera.net>\r
+References: <1396401381-18128-1-git-send-email-david@tethera.net>\r
+X-BeenThere: notmuch@notmuchmail.org\r
+X-Mailman-Version: 2.1.13\r
+Precedence: list\r
+List-Id: "Use and development of the notmuch mail system."\r
+ <notmuch.notmuchmail.org>\r
+List-Unsubscribe: <http://notmuchmail.org/mailman/options/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=unsubscribe>\r
+List-Archive: <http://notmuchmail.org/pipermail/notmuch>\r
+List-Post: <mailto:notmuch@notmuchmail.org>\r
+List-Help: <mailto:notmuch-request@notmuchmail.org?subject=help>\r
+List-Subscribe: <http://notmuchmail.org/mailman/listinfo/notmuch>,\r
+ <mailto:notmuch-request@notmuchmail.org?subject=subscribe>\r
+X-List-Received-Date: Wed, 02 Apr 2014 01:16:42 -0000\r
+\r
+It is useful to able to tell whether a dump completed successfully in\r
+situtions where we don't have access to the return code.\r
+---\r
+ notmuch-dump.c | 61 +++++++++++++++++++++++++++++++++++++++++++++-------------\r
+ 1 file changed, 48 insertions(+), 13 deletions(-)\r
+\r
+diff --git a/notmuch-dump.c b/notmuch-dump.c\r
+index 28342b7..05ed6b4 100644\r
+--- a/notmuch-dump.c\r
++++ b/notmuch-dump.c\r
+@@ -129,30 +129,65 @@ notmuch_database_dump (notmuch_database_t *notmuch,\r
+ {\r
+ gzFile output;\r
+ const char *mode = gzip_output ? "w9" : "wT";\r
++ const char *name_for_error = output_file_name ? output_file_name : "stdout";\r
+ \r
+- int ret;\r
++ char *tempname = NULL;\r
++ int outfd = -1;\r
++\r
++ int ret = -1;\r
++\r
++ if (output_file_name) {\r
++ tempname = talloc_asprintf (notmuch, "%s.XXXXXX", output_file_name);\r
++ outfd = mkstemp (tempname);\r
++ } else {\r
++ outfd = fileno (stdout);\r
++ }\r
+ \r
+- if (output_file_name)\r
+- output = gzopen (output_file_name, mode);\r
+- else\r
+- output = gzdopen (fileno (stdout), mode);\r
++ if (outfd < 0) {\r
++ fprintf (stderr, "Bad output file %s\n", name_for_error);\r
++ goto DONE;\r
++ }\r
++\r
++ output = gzdopen (outfd, mode);\r
+ \r
+ if (output == NULL) {\r
+ fprintf (stderr, "Error opening %s for (gzip) writing: %s\n",\r
+- output_file_name ? output_file_name : "stdout", strerror (errno));\r
+- return EXIT_FAILURE;\r
++ name_for_error, strerror (errno));\r
++ goto DONE;\r
+ }\r
+ \r
+ ret = database_dump_file (notmuch, output, query_str, output_format);\r
++ if (ret) goto DONE;\r
+ \r
+- if (gzflush (output, Z_FINISH)) {\r
+- fprintf (stderr, "Error flushing output: %s\n",\r
+- gzerror (output, NULL));\r
+- return EXIT_FAILURE;\r
++ ret = gzflush (output, Z_FINISH);\r
++ if (ret) {\r
++ fprintf (stderr, "Error flushing output: %s\n", gzerror (output, NULL));\r
++ goto DONE;\r
+ }\r
+ \r
+- if (output_file_name)\r
+- gzclose_w (output);\r
++ ret = fdatasync (outfd);\r
++ if (ret) {\r
++ perror ("fdatasync");\r
++ goto DONE;\r
++ }\r
++\r
++ if (output_file_name) {\r
++ ret = gzclose_w (output);\r
++ if (ret != Z_OK) {\r
++ ret = EXIT_FAILURE;\r
++ goto DONE;\r
++ }\r
++\r
++ ret = rename (tempname, output_file_name);\r
++ if (ret) {\r
++ perror ("rename");\r
++ goto DONE;\r
++ }\r
++\r
++ }\r
++ DONE:\r
++ if (ret != EXIT_SUCCESS && output_file_name)\r
++ (void) unlink (tempname);\r
+ \r
+ return ret;\r
+ }\r
+-- \r
+1.9.0\r
+\r