X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=blobdiff_plain;f=notmuch-insert.c;h=a1d564c78cd1eb0f52b126de7c7c4dd257c87888;hp=ccb091ac0561f1af3ceb1f2daefd0e26f7990e88;hb=dcfcb4ba7b9dfdb49ec62d8fb47a72fb60540655;hpb=c878081127f48c393835b6f067f8f85beda9ff29 diff --git a/notmuch-insert.c b/notmuch-insert.c index ccb091ac..a1d564c7 100644 --- a/notmuch-insert.c +++ b/notmuch-insert.c @@ -67,20 +67,21 @@ safe_gethostname (char *hostname, size_t len) static notmuch_bool_t sync_dir (const char *dir) { - notmuch_bool_t ret; - int fd; + int fd, r; fd = open (dir, O_RDONLY); if (fd == -1) { - fprintf (stderr, "Error: open() dir failed: %s\n", strerror (errno)); + fprintf (stderr, "Error: open %s: %s\n", dir, strerror (errno)); return FALSE; } - ret = (fsync (fd) == 0); - if (! ret) { - fprintf (stderr, "Error: fsync() dir failed: %s\n", strerror (errno)); - } + + r = fsync (fd); + if (r) + fprintf (stderr, "Error: fsync %s: %s\n", dir, strerror (errno)); + close (fd); - return ret; + + return r == 0; } /* @@ -103,97 +104,104 @@ is_valid_folder_name (const char *folder) } } -/* Make the given directory, succeeding if it already exists. */ +/* + * 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 notmuch_bool_t -make_directory (char *path, int mode) +mkdir_recursive (const void *ctx, const char *path, int mode) { - notmuch_bool_t ret; - char *slash; + struct stat st; + int r; + char *parent = NULL, *slash; - if (mkdir (path, mode) != 0) - return (errno == EEXIST); + /* 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; + } - /* Sync the parent directory for durability. */ - ret = TRUE; - slash = strrchr (path, '/'); - if (slash) { - *slash = '\0'; - ret = sync_dir (path); - *slash = '/'; + return TRUE; + } else if (errno != ENOENT) { + fprintf (stderr, "Error: stat '%s': %s\n", path, strerror (errno)); + return FALSE; } - return ret; -} - -/* Make the given directory including its parent directories as necessary. - * Return TRUE on success, FALSE on error. */ -static notmuch_bool_t -make_directory_and_parents (char *path, int mode) -{ - struct stat st; - char *start; - char *end; - notmuch_bool_t ret; - /* First check the common case: directory already exists. */ - if (stat (path, &st) == 0) - return S_ISDIR (st.st_mode) ? TRUE : FALSE; - - for (start = path; *start != '\0'; start = end + 1) { - /* start points to the first unprocessed character. - * Find the next slash from start onwards. */ - end = strchr (start, '/'); - - /* If there are no more slashes then all the parent directories - * have been made. Now attempt to make the whole path. */ - if (end == NULL) - return make_directory (path, mode); - - /* Make the path up to the next slash, unless the current - * directory component is actually empty. */ - if (end > start) { - *end = '\0'; - ret = make_directory (path, mode); - *end = '/'; - if (! ret) - 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; } - return TRUE; + 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. dir and its subdirectories - * 'cur', 'new', 'tmp'. */ +/* + * Create the given maildir folder, i.e. maildir and its + * subdirectories cur/new/tmp. Return TRUE on success, FALSE + * otherwise. Partial results are not cleaned up on errors. + */ static notmuch_bool_t -maildir_create_folder (void *ctx, const char *dir) +maildir_create_folder (const void *ctx, const char *maildir) { + const char *subdirs[] = { "cur", "new", "tmp" }; const int mode = 0700; char *subdir; - char *tail; + unsigned int i; - /* Create 'cur' directory, including parent directories. */ - subdir = talloc_asprintf (ctx, "%s/cur", dir); - if (! subdir) { - fprintf (stderr, "Out of memory.\n"); - return FALSE; + for (i = 0; i < ARRAY_SIZE (subdirs); i++) { + subdir = talloc_asprintf (ctx, "%s/%s", maildir, subdirs[i]); + if (! subdir) { + fprintf (stderr, "Error: %s\n", strerror (ENOMEM)); + return FALSE; + } + + if (! mkdir_recursive (ctx, subdir, mode)) + return FALSE; } - if (! make_directory_and_parents (subdir, mode)) - return FALSE; - tail = subdir + strlen (subdir) - 3; + return TRUE; +} - /* Create 'new' directory. */ - strcpy (tail, "new"); - if (! make_directory (subdir, mode)) - return FALSE; +/* + * Generate a temporary file basename, no path, do not create an + * actual file. Return the basename, or NULL on errors. + */ +static char * +tempfilename (const void *ctx) +{ + char *filename; + char hostname[256]; + struct timeval tv; + pid_t pid; - /* Create 'tmp' directory. */ - strcpy (tail, "tmp"); - if (! make_directory (subdir, mode)) - return FALSE; + /* We follow the Dovecot file name generation algorithm. */ + pid = getpid (); + safe_gethostname (hostname, sizeof (hostname)); + gettimeofday (&tv, NULL); - talloc_free (subdir); - return TRUE; + filename = talloc_asprintf (ctx, "%ld.M%ldP%d.%s", + tv.tv_sec, tv.tv_usec, pid, hostname); + if (! filename) + fprintf (stderr, "Error: %s\n", strerror (ENOMEM)); + + return filename; } /* Open a unique file in the 'tmp' sub-directory of dir. @@ -205,23 +213,13 @@ static int maildir_open_tmp_file (void *ctx, const char *dir, char **tmppath, char **newpath, char **newdir) { - pid_t pid; - char hostname[256]; - struct timeval tv; char *filename; int fd = -1; - /* We follow the Dovecot file name generation algorithm. */ - pid = getpid (); - safe_gethostname (hostname, sizeof (hostname)); do { - gettimeofday (&tv, NULL); - filename = talloc_asprintf (ctx, "%ld.M%ldP%d.%s", - tv.tv_sec, tv.tv_usec, pid, hostname); - if (! filename) { - fprintf (stderr, "Out of memory\n"); + filename = tempfilename (ctx); + if (! filename) return -1; - } *tmppath = talloc_asprintf (ctx, "%s/tmp/%s", dir, filename); if (! *tmppath) { @@ -251,11 +249,12 @@ maildir_open_tmp_file (void *ctx, const char *dir, return fd; } -/* Copy the contents of standard input (fdin) into fdout. - * Returns TRUE if a non-empty file was written successfully. - * Otherwise, return FALSE. */ +/* + * Copy fdin to fdout, return TRUE on success, and FALSE on errors and + * empty input. + */ static notmuch_bool_t -copy_stdin (int fdin, int fdout) +copy_fd (int fdout, int fdin) { notmuch_bool_t empty = TRUE; @@ -308,7 +307,7 @@ write_message (void *ctx, int fdin, const char *dir, char **newpath) cleanup_path = tmppath; - if (! copy_stdin (fdin, fdout)) + if (! copy_fd (fdout, fdin)) goto FAIL; if (fsync (fdout) != 0) { @@ -461,11 +460,8 @@ notmuch_insert_command (notmuch_config_t *config, int argc, char *argv[]) fprintf (stderr, "Out of memory\n"); return EXIT_FAILURE; } - if (create_folder && ! maildir_create_folder (config, maildir)) { - fprintf (stderr, "Error: creating maildir %s: %s\n", - maildir, strerror (errno)); + if (create_folder && ! maildir_create_folder (config, maildir)) return EXIT_FAILURE; - } } /* Setup our handler for SIGINT. We do not set SA_RESTART so that copying