]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
istream-seekable: Changed API to use a callback function to create the temp file.
authorTimo Sirainen <tss@iki.fi>
Tue, 26 May 2009 02:18:39 +0000 (22:18 -0400)
committerTimo Sirainen <tss@iki.fi>
Tue, 26 May 2009 02:18:39 +0000 (22:18 -0400)
--HG--
branch : HEAD

src/lda/main.c
src/lib/istream-seekable.c
src/lib/istream-seekable.h

index e9c65302af7f105d339b8cb87f086facbd832929..2fbe54e2d5c2763f35b0cb28f2701b11b2a46ae0 100644 (file)
@@ -4,8 +4,10 @@
 #include "lib-signals.h"
 #include "env-util.h"
 #include "fd-set-nonblock.h"
+#include "close-keep-errno.h"
 #include "istream.h"
 #include "istream-seekable.h"
+#include "safe-mkstemp.h"
 #include "str.h"
 #include "str-sanitize.h"
 #include "strescape.h"
@@ -82,10 +84,35 @@ static const char *address_sanitize(const char *address)
        return ret;
 }
 
+static int seekable_fd_callback(const char **path_r, void *context)
+{
+       struct mail_deliver_context *ctx = context;
+       string_t *path;
+       int fd;
+
+       path = t_str_new(128);
+       str_append(path, mail_user_get_temp_prefix(ctx->dest_user));
+       fd = safe_mkstemp(path, 0600, (uid_t)-1, (gid_t)-1);
+       if (fd == -1) {
+               i_error("safe_mkstemp(%s) failed: %m", str_c(path));
+               return -1;
+       }
+
+       /* we just want the fd, unlink it */
+       if (unlink(str_c(path)) < 0) {
+               /* shouldn't happen.. */
+               i_error("unlink(%s) failed: %m", str_c(path));
+               close_keep_errno(fd);
+               return -1;
+       }
+
+       *path_r = str_c(path);
+       return fd;
+}
 
 static struct istream *
 create_raw_stream(struct mail_deliver_context *ctx,
-                 const char *temp_path_prefix, int fd, time_t *mtime_r)
+                 int fd, time_t *mtime_r)
 {
        struct istream *input, *input2, *input_list[2];
        const unsigned char *data;
@@ -135,7 +162,7 @@ create_raw_stream(struct mail_deliver_context *ctx,
 
        input_list[0] = input2; input_list[1] = NULL;
        input = i_stream_create_seekable(input_list, MAIL_MAX_MEMORY_BUFFER,
-                                        temp_path_prefix);
+                                        seekable_fd_callback, ctx);
        i_stream_unref(&input2);
        return input;
 }
@@ -349,8 +376,7 @@ int main(int argc, char *argv[])
        if (mail_storage_create(raw_ns, "raw", 0, &errstr) < 0)
                i_fatal("Couldn't create internal raw storage: %s", errstr);
        if (path == NULL) {
-               const char *prefix = mail_user_get_temp_prefix(ctx.dest_user);
-               input = create_raw_stream(&ctx, prefix, 0, &mtime);
+               input = create_raw_stream(&ctx, 0, &mtime);
                box = mailbox_open(&raw_ns->storage, "Dovecot Delivery Mail",
                                   input, MAILBOX_OPEN_NO_INDEX_FILES);
                i_stream_unref(&input);
index 4d7398539ead8f663d9d0560eb26a0ebfe4b46d4..48705743a82c6c1e6dab6c025d4f546cf7a82152 100644 (file)
@@ -3,26 +3,22 @@
 #include "lib.h"
 #include "buffer.h"
 #include "close-keep-errno.h"
-#include "hex-binary.h"
-#include "randgen.h"
 #include "write-full.h"
 #include "istream-internal.h"
 #include "istream-concat.h"
 #include "istream-seekable.h"
 
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <time.h>
-
 #define BUF_INITIAL_SIZE (1024*32)
 
 struct seekable_istream {
        struct istream_private istream;
 
-       char *temp_prefix;
+       char *temp_path;
        uoff_t write_peak;
 
+       int (*fd_callback)(const char **path_r, void *context);
+       void *context;
+
        buffer_t *buffer;
        struct istream **input, *cur_input;
        struct istream *fd_input;
@@ -54,7 +50,7 @@ static void i_stream_seekable_destroy(struct iostream_private *stream)
        for (i = 0; sstream->input[i] != NULL; i++)
                i_stream_unref(&sstream->input[i]);
 
-       i_free(sstream->temp_prefix);
+       i_free(sstream->temp_path);
 }
 
 static void
@@ -73,44 +69,14 @@ i_stream_seekable_set_max_buffer_size(struct iostream_private *stream,
 
 static int copy_to_temp_file(struct seekable_istream *sstream)
 {
-       unsigned char randbuf[8];
        const char *path;
-       struct stat st;
        int fd;
 
-       /* create a temporary file */
-       for (;;) {
-               random_fill_weak(randbuf, sizeof(randbuf));
-               path = t_strconcat(sstream->temp_prefix,
-                                  dec2str(time(NULL)), ".",
-                                  dec2str(getpid()), ".",
-                                  binary_to_hex(randbuf, sizeof(randbuf)),
-                                  NULL);
-               if (stat(path, &st) == 0)
-                       continue;
-
-               if (errno != ENOENT) {
-                       i_error("stat(%s) failed: %m", path);
-                       return -1;
-               }
-
-               fd = open(path, O_RDWR | O_EXCL | O_CREAT, 0600);
-               if (fd != -1)
-                       break;
-
-               if (errno != EEXIST) {
-                       i_error("creat(%s) failed: %m", path);
-                       return -1;
-               }
-       }
-
-       /* we just want the fd, unlink it */
-       if (unlink(path) < 0) {
-               /* shouldn't happen.. */
-               i_error("unlink(%s) failed: %m", path);
-               close_keep_errno(fd);
+       fd = sstream->fd_callback(&path, sstream->context);
+       if (fd == -1)
                return -1;
-       }
+
+       sstream->temp_path = i_strdup(path);
 
        /* copy our currently read buffer to it */
        if (write_full(fd, sstream->buffer->data, sstream->buffer->used) < 0) {
@@ -231,8 +197,8 @@ static ssize_t i_stream_seekable_read(struct istream_private *stream)
                if (write_full(sstream->fd, data, size) < 0) {
                        i_assert(errno != 0);
                        stream->istream.stream_errno = errno;
-                       i_error("write_full(%s...) failed: %m",
-                               sstream->temp_prefix);
+                       i_error("write_full(%s) failed: %m",
+                               sstream->temp_path);
                        i_stream_close(&stream->istream);
                        return -1;
                }
@@ -303,7 +269,9 @@ i_stream_seekable_stat(struct istream_private *stream, bool exact)
 
 struct istream *
 i_stream_create_seekable(struct istream *input[],
-                        size_t max_buffer_size, const char *temp_prefix)
+                        size_t max_buffer_size,
+                        int (*fd_callback)(const char **path_r, void *context),
+                        void *context)
 {
        struct seekable_istream *sstream;
        const unsigned char *data;
@@ -328,7 +296,8 @@ i_stream_create_seekable(struct istream *input[],
        i_assert(count != 0);
 
        sstream = i_new(struct seekable_istream, 1);
-       sstream->temp_prefix = i_strdup(temp_prefix);
+       sstream->fd_callback = fd_callback;
+       sstream->context = context;
        sstream->buffer = buffer_create_dynamic(default_pool, BUF_INITIAL_SIZE);
         sstream->istream.max_buffer_size = max_buffer_size;
 
index 13f65a205bc784681c93f8b1d21756ac53f81ba4..305e0a43290c8727786e64e91f72e64d191a0cc6 100644 (file)
@@ -4,10 +4,13 @@
 /* Create a seekable stream from given NULL-terminated list of input streams.
    Try to keep it in memory, but use a temporary file if it's too large.
 
-   temp_prefix is used as path and filename prefix for creating the file.
-   It will be appended by PID, timestamp and 128 bits of weak randomness. */
+   When max_buffer_size is reached, fd_callback is called. It should return
+   the fd and path of the created file. Typically the callback would also
+   unlink the file before returning. */
 struct istream *
 i_stream_create_seekable(struct istream *input[],
-                        size_t max_buffer_size, const char *temp_prefix);
+                        size_t max_buffer_size,
+                        int (*fd_callback)(const char **path_r, void *context),
+                        void *context);
 
 #endif