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 _______________________________________________ notmuch mailing list -- notmuch@notmuchmail.org To unsubscribe send an email to notmuch-leave@notmuchmail.org