X-Git-Url: https://git.notmuchmail.org/git?a=blobdiff_plain;f=contrib%2Fnotmuch-deliver%2Fsrc%2Fmain.c;h=f7a4eaa6576bd1ec544d54c54b0e3d6e158388d0;hb=c39fd2a479cf28978236de0e9fc0304a8eda4e6e;hp=1fece76fe49c64d26decb228be5ec362368e7e9c;hpb=af863f8c7f1f1571df4f1172ec4e963fa654945e;p=notmuch diff --git a/contrib/notmuch-deliver/src/main.c b/contrib/notmuch-deliver/src/main.c index 1fece76f..f7a4eaa6 100644 --- a/contrib/notmuch-deliver/src/main.c +++ b/contrib/notmuch-deliver/src/main.c @@ -26,7 +26,12 @@ #include #include #include +#ifdef HAVE_UNISTD_H #include +#endif +#ifdef HAVE_SPLICE +#include +#endif #ifdef HAVE_SYSEXITS_H #include @@ -136,32 +141,60 @@ load_keyfile(const gchar *path, gchar **db_path, gchar ***tags) return TRUE; } +#ifdef HAVE_SPLICE static int -save_maildir(int fdin, const char *dir, int auto_create, char **path) +save_splice(int fdin, int fdout) { - int fd, ret, written; - char buf[4096], *p; - struct maildir_tmpcreate_info info; + int ret, written, pfd[2]; - maildir_tmpcreate_init(&info); - info.openmode = 0666; - info.maildir = dir; - info.doordie = 1; + if (pipe(pfd) < 0) { + g_critical("Failed to create pipe: %s", g_strerror(errno)); + return EX_IOERR; + } - while ((fd = maildir_tmpcreate_fd(&info)) < 0) - { - if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0) - { - auto_create = 0; - continue; + for (;;) { + ret = splice(fdin, NULL, pfd[1], NULL, 4096, 0); + if (!ret) + break; + if (ret < 0) { + g_critical("Splicing data from standard input failed: %s", + g_strerror(errno)); + close(pfd[0]); + close(pfd[1]); + return EX_IOERR; } - g_critical("Failed to create temporary file `%s': %s", - info.tmpname, g_strerror(errno)); - return EX_TEMPFAIL; + do { + written = splice(pfd[0], NULL, fdout, NULL, ret, 0); + if (!written) { + g_critical("Splicing data to temporary file failed: internal error"); + close(pfd[0]); + close(pfd[1]); + return EX_IOERR; + } + if (written < 0) { + g_critical("Splicing data to temporary file failed: %s", + g_strerror(errno)); + close(pfd[0]); + close(pfd[1]); + return EX_IOERR; + } + ret -= written; + } while (ret); } - g_debug("Reading from standard input and writing to `%s'", info.tmpname); + close(pfd[0]); + close(pfd[1]); + return 0; +} +#endif /* HAVE_SPLICE */ + +static int +save_readwrite(int fdin, int fdout) +{ + int ret, written; + char buf[4096], *p; + for (;;) { ret = read(fdin, buf, 4096); if (!ret) @@ -169,27 +202,66 @@ save_maildir(int fdin, const char *dir, int auto_create, char **path) if (ret < 0) { if (errno == EINTR) continue; - g_critical("Reading from standard input failed: %s", g_strerror(errno)); - goto fail; + g_critical("Reading from standard input failed: %s", + g_strerror(errno)); + return EX_IOERR; } p = buf; do { - written = write(fd, p, ret); + written = write(fdout, p, ret); if (!written) - goto fail; + return EX_IOERR; if (written < 0) { if (errno == EINTR) continue; - g_critical("Writing to temporary file `%s' failed: %s", - info.tmpname, g_strerror(errno)); - goto fail; + g_critical("Writing to temporary file failed: %s", + g_strerror(errno)); + return EX_IOERR; } p += written; ret -= written; } while (ret); } - close(fd); + return 0; +} + +static int +save_maildir(int fdin, const char *dir, int auto_create, char **path) +{ + int fdout, ret; + struct maildir_tmpcreate_info info; + + maildir_tmpcreate_init(&info); + info.openmode = 0666; + info.maildir = dir; + info.doordie = 1; + + while ((fdout = maildir_tmpcreate_fd(&info)) < 0) + { + if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0) + { + auto_create = 0; + continue; + } + + g_critical("Failed to create temporary file `%s': %s", + info.tmpname, g_strerror(errno)); + return EX_TEMPFAIL; + } + + g_debug("Reading from standard input and writing to `%s'", info.tmpname); +#ifdef HAVE_SPLICE + ret = g_getenv("NOTMUCH_DELIVER_NO_SPLICE") + ? save_readwrite(fdin, fdout) + : save_splice(fdin, fdout); +#else + ret = save_readwrite(fdin, fdout); +#endif /* HAVE_SPLICE */ + if (ret) + goto fail; + + close(fdout); g_debug("Moving `%s' to `%s'", info.tmpname, info.newname); if (maildir_movetmpnew(info.tmpname, info.newname)) { g_critical("Moving `%s' to `%s' failed: %s", @@ -261,6 +333,7 @@ save_database(notmuch_database_t *db, const char *path, char **default_tags) case NOTMUCH_STATUS_SUCCESS: break; case NOTMUCH_STATUS_DUPLICATE_MESSAGE_ID: + g_debug("Message is a duplicate, not adding tags"); return 0; default: g_warning("Failed to add `%s' to notmuch database: %s", @@ -292,8 +365,11 @@ main(int argc, char **argv) g_option_context_set_description(ctx, "\nConfiguration:\n" " "PACKAGE" uses notmuch's configuration file to determine database path and\n" - "initial tags to add to new messages. You may set NOTMUCH_CONFIG environment\n" - "variable to specify an alternative configuration file.\n" + " initial tags to add to new messages. You may set NOTMUCH_CONFIG environment\n" + " variable to specify an alternative configuration file.\n" + "\nEnvironment:\n" + " NOTMUCH_CONFIG: Path to notmuch configuration file\n" + " NOTMUCH_DELIVER_NO_SPLICE: Don't use splice() even if it's available\n" "\nExit codes:\n" " 0 => Successful run\n" " 64 => Usage error\n" @@ -303,7 +379,7 @@ main(int argc, char **argv) " (failed to read from standard input)\n" " (failed to write to temporary file)\n" " 76 => Failed to open/create maildir\n" - " 78 => Configuration error (wrt .notmuch-config\n"); + " 78 => Configuration error (wrt .notmuch-config)\n"); g_log_set_default_handler(log_handler, NULL); @@ -338,6 +414,11 @@ main(int argc, char **argv) } g_free(conf_path); + if ((argc - 1) > 1) { + g_critical("Won't deliver to %d folders", argc - 1); + return EX_USAGE; + } + if (argc > 1) { folder = g_strdup_printf("%s%s", opt_folder ? "." : "", argv[1]); maildir = g_build_filename(db_path, folder, NULL); @@ -364,6 +445,7 @@ main(int argc, char **argv) g_free(maildir); if ((ret = save_database(db, mail, conf_tags)) != 0 && opt_fatal) { + g_warning("Unlinking `%s'", mail); unlink(mail); return ret; }