From: Ali Polatel Date: Wed, 26 May 2010 11:21:15 +0000 (+0300) Subject: notmuch-deliver: Use splice() if it's available X-Git-Tag: 0.10_rc1~51 X-Git-Url: https://git.notmuchmail.org/git?p=notmuch;a=commitdiff_plain;h=73258fec796b57c757e10b0baec306157a69edeb notmuch-deliver: Use splice() if it's available NOTMUCH_DELIVER_NO_SPLICE environment variable may be set to fallback to the read/write method. --- diff --git a/contrib/notmuch-deliver/configure.ac b/contrib/notmuch-deliver/configure.ac index 9d16af16..b6142bce 100644 --- a/contrib/notmuch-deliver/configure.ac +++ b/contrib/notmuch-deliver/configure.ac @@ -67,7 +67,7 @@ AC_STRUCT_TM dnl }}} dnl {{{ Check for library functions -AC_CHECK_FUNCS([setgroups initgroups symlink readlink strcasecmp utime utimes]) +AC_CHECK_FUNCS([setgroups initgroups symlink readlink strcasecmp utime utimes splice]) dnl }}} dnl {{{ gethostname() diff --git a/contrib/notmuch-deliver/src/main.c b/contrib/notmuch-deliver/src/main.c index 49919ff1..7c314911 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,61 @@ 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: %s", + g_strerror(errno)); + 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 +203,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", @@ -295,6 +368,9 @@ main(int argc, char **argv) " "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" + "\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"