unofficial mirror of notmuch@notmuchmail.org
 help / color / mirror / code / Atom feed
From: David Bremner <david@tethera.net>
To: notmuch@notmuchmail.org
Subject: [PATCH 1/5] util: refactor sync_dir and mkdir_recursive
Date: Wed, 28 Aug 2024 08:45:54 -0700	[thread overview]
Message-ID: <20240828160710.866567-2-david@tethera.net> (raw)
In-Reply-To: <20240828160710.866567-1-david@tethera.net>

Moving these functions to libnotmuch_util will allow re-user from
either multiple CLI compilation units or from the library. To avoid
future surprises, replace printing to stderr with the usual status
string mechanism.
---
 notmuch-insert.c | 84 +++++------------------------------------
 util/path-util.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++-
 util/path-util.h |  8 ++++
 3 files changed, 114 insertions(+), 75 deletions(-)

diff --git a/notmuch-insert.c b/notmuch-insert.c
index e44607ad..66c4f434 100644
--- a/notmuch-insert.c
+++ b/notmuch-insert.c
@@ -21,13 +21,13 @@
  * Author: Peter Wang <novalazy@gmail.com>
  */
 
-#include "notmuch-client.h"
-#include "tag-util.h"
 
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <fcntl.h>
+
+#include "notmuch-client.h"
+#include "tag-util.h"
 #include "string-util.h"
+#include "path-util.h"
 
 static volatile sig_atomic_t interrupted;
 
@@ -64,26 +64,6 @@ safe_gethostname (char *hostname, size_t len)
     }
 }
 
-/* Call fsync() on a directory path. */
-static bool
-sync_dir (const char *dir)
-{
-    int fd, r;
-
-    fd = open (dir, O_RDONLY);
-    if (fd == -1) {
-	fprintf (stderr, "Error: open %s: %s\n", dir, strerror (errno));
-	return false;
-    }
-
-    r = fsync (fd);
-    if (r)
-	fprintf (stderr, "Error: fsync %s: %s\n", dir, strerror (errno));
-
-    close (fd);
-
-    return r == 0;
-}
 
 /*
  * Check the specified folder name does not contain a directory
@@ -105,54 +85,6 @@ is_valid_folder_name (const char *folder)
     }
 }
 
-/*
- * Make the given directory and its parents as necessary, using the
- * given mode. Return true on success, false otherwise. Partial
- * results are not cleaned up on errors.
- */
-static bool
-mkdir_recursive (const void *ctx, const char *path, int mode)
-{
-    struct stat st;
-    int r;
-    char *parent = NULL, *slash;
-
-    /* First check the common case: directory already exists. */
-    r = stat (path, &st);
-    if (r == 0) {
-	if (! S_ISDIR (st.st_mode)) {
-	    fprintf (stderr, "Error: '%s' is not a directory: %s\n",
-		     path, strerror (EEXIST));
-	    return false;
-	}
-
-	return true;
-    } else if (errno != ENOENT) {
-	fprintf (stderr, "Error: stat '%s': %s\n", path, strerror (errno));
-	return false;
-    }
-
-    /* mkdir parents, if any */
-    slash = strrchr (path, '/');
-    if (slash && slash != path) {
-	parent = talloc_strndup (ctx, path, slash - path);
-	if (! parent) {
-	    fprintf (stderr, "Error: %s\n", strerror (ENOMEM));
-	    return false;
-	}
-
-	if (! mkdir_recursive (ctx, parent, mode))
-	    return false;
-    }
-
-    if (mkdir (path, mode)) {
-	fprintf (stderr, "Error: mkdir '%s': %s\n", path, strerror (errno));
-	return false;
-    }
-
-    return parent ? sync_dir (parent) : true;
-}
-
 /*
  * Create the given maildir folder, i.e. maildir and its
  * subdirectories cur/new/tmp. Return true on success, false
@@ -165,6 +97,7 @@ maildir_create_folder (const void *ctx, const char *maildir, bool world_readable
     const int mode = (world_readable ? 0755 : 0700);
     char *subdir;
     unsigned int i;
+    char **status_string = NULL;
 
     for (i = 0; i < ARRAY_SIZE (subdirs); i++) {
 	subdir = talloc_asprintf (ctx, "%s/%s", maildir, subdirs[i]);
@@ -173,7 +106,7 @@ maildir_create_folder (const void *ctx, const char *maildir, bool world_readable
 	    return false;
 	}
 
-	if (! mkdir_recursive (ctx, subdir, mode))
+	if (mkdir_recursive (ctx, subdir, mode, status_string))
 	    return false;
     }
 
@@ -347,6 +280,7 @@ static char *
 maildir_write_new (const void *ctx, int fdin, const char *maildir, bool world_readable)
 {
     char *cleanpath, *tmppath, *newpath, *newdir;
+    char *status_string = NULL;
 
     tmppath = maildir_write_tmp (ctx, fdin, maildir, world_readable);
     if (! tmppath)
@@ -375,13 +309,15 @@ maildir_write_new (const void *ctx, int fdin, const char *maildir, bool world_re
 	goto FAIL;
     }
 
-    if (! sync_dir (newdir))
+    if (sync_dir (newdir, &status_string))
 	goto FAIL;
 
     return newpath;
 
   FAIL:
     unlink (cleanpath);
+    if (status_string)
+	fputs (status_string, stderr);
 
     return NULL;
 }
diff --git a/util/path-util.c b/util/path-util.c
index 3267a967..b7114b18 100644
--- a/util/path-util.c
+++ b/util/path-util.c
@@ -5,10 +5,17 @@
 #define _GNU_SOURCE
 
 #include "path-util.h"
-
+#include "compat.h"
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
 #include <limits.h>
 #include <stdlib.h>
 
+#include <talloc.h>
 
 char *
 notmuch_canonicalize_file_name (const char *path)
@@ -25,3 +32,91 @@ notmuch_canonicalize_file_name (const char *path)
 #error undefined PATH_MAX _and_ missing canonicalize_file_name not supported
 #endif
 }
+
+/* Call fsync() on a directory path. */
+notmuch_status_t 
+sync_dir (const char *dir, char **status_string)
+{
+    int fd, r;
+
+    fd = open (dir, O_RDONLY);
+    if (fd == -1) {
+	if (status_string)
+	    IGNORE_RESULT (asprintf (status_string,
+				     "Error: open %s: %s\n", dir, strerror (errno)));
+	return NOTMUCH_STATUS_FILE_ERROR;
+    }
+
+    r = fsync (fd);
+    if (r && status_string)
+	IGNORE_RESULT (asprintf (status_string,
+				 "Error: fsync %s: %s\n", dir, strerror (errno)));
+
+    close (fd);
+
+    return r == 0 ? NOTMUCH_STATUS_SUCCESS : NOTMUCH_STATUS_FILE_ERROR;
+}
+
+/*
+ * Make the given directory and its parents as necessary, using the
+ * given mode. Partial results are not cleaned up on errors.
+ */
+notmuch_status_t
+mkdir_recursive (const void *ctx, const char *path, int mode,
+		 char **status_string)
+{
+    notmuch_status_t status;
+    struct stat st;
+    int r;
+    char *parent = NULL, *slash;
+
+    /* First check the common case: directory already exists. */
+    r = stat (path, &st);
+    if (r == 0) {
+	if (! S_ISDIR (st.st_mode)) {
+	    if (status_string)
+		IGNORE_RESULT(asprintf (status_string, "Error: '%s' is not a directory: %s\n",
+					path, strerror (EEXIST)));
+	    return NOTMUCH_STATUS_FILE_ERROR;
+	}
+
+	return NOTMUCH_STATUS_SUCCESS;
+    } else if (errno != ENOENT) {
+	    if (status_string)
+		IGNORE_RESULT(asprintf (status_string,
+					"Error: stat '%s': %s\n", path, strerror (errno)));
+	return NOTMUCH_STATUS_FILE_ERROR;
+    }
+
+    /* mkdir parents, if any */
+    slash = strrchr (path, '/');
+    if (slash && slash != path) {
+	parent = talloc_strndup (ctx, path, slash - path);
+	if (! parent) {
+	    if (status_string)
+		IGNORE_RESULT(asprintf (status_string,
+					"Error: %s\n",
+					strerror (ENOMEM)));
+	    return NOTMUCH_STATUS_FILE_ERROR;
+	}
+
+	status = mkdir_recursive (ctx, parent, mode, status_string);
+	if (status)
+	    return status;
+    }
+
+    if (mkdir (path, mode)) {
+	    if (status_string)
+		IGNORE_RESULT(asprintf (status_string,
+					"Error: mkdir '%s': %s\n",
+					path, strerror (errno)));
+	return NOTMUCH_STATUS_FILE_ERROR;
+    }
+
+    if (parent) {
+	status = sync_dir (parent, status_string);
+	if (status)
+	    return status;
+    }
+    return NOTMUCH_STATUS_SUCCESS;
+}
diff --git a/util/path-util.h b/util/path-util.h
index ac85f696..fcdaf626 100644
--- a/util/path-util.h
+++ b/util/path-util.h
@@ -5,6 +5,8 @@
 #ifndef NOTMUCH_UTIL_PATH_UTIL_H_
 #define NOTMUCH_UTIL_PATH_UTIL_H_
 
+#include "notmuch.h"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -12,6 +14,12 @@ extern "C" {
 char *
 notmuch_canonicalize_file_name (const char *path);
 
+notmuch_status_t
+mkdir_recursive (const void *ctx, const char *path, int mode, char **status_string);
+
+notmuch_status_t
+sync_dir (const char *path, char **status_string);
+    
 #ifdef __cplusplus
 }
 #endif
-- 
2.43.0

  reply	other threads:[~2024-08-28 16:18 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-08-28 15:45 WIP: git-remote-notmuch David Bremner
2024-08-28 15:45 ` David Bremner [this message]
2024-08-28 15:45 ` [PATCH 2/5] cli: start remote helper for git David Bremner
2024-08-28 15:45 ` [PATCH 3/5] cli/git-remote: add support for import command David Bremner
2024-08-28 15:45 ` [PATCH 4/5] cli/git-remote: add export command David Bremner
2024-08-28 15:45 ` [PATCH 5/5] cli/git-remote: add time performance test David Bremner
2024-08-28 21:11 ` WIP: git-remote-notmuch David Bremner

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://notmuchmail.org/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240828160710.866567-2-david@tethera.net \
    --to=david@tethera.net \
    --cc=notmuch@notmuchmail.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://yhetil.org/notmuch.git/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).