# HG changeset patch # User Timo Sirainen # Date 1243304335 14400 # Node ID 82949209612e58964db48d7b4fddc0d81fd72616 # Parent 616c0ee81222740ffae563c29e33edf5a18a7203 istream-seekable: Changed API to use a callback function to create the temp file. diff -r 616c0ee81222 -r 82949209612e src/deliver/deliver.c --- a/src/deliver/deliver.c Mon May 25 21:53:13 2009 -0400 +++ b/src/deliver/deliver.c Mon May 25 22:18:55 2009 -0400 @@ -19,6 +19,8 @@ #include "str.h" #include "str-sanitize.h" #include "strescape.h" +#include "safe-mkstemp.h" +#include "close-keep-errno.h" #include "var-expand.h" #include "rfc822-parser.h" #include "message-address.h" @@ -609,9 +611,34 @@ return ret; } +static int seekable_fd_callback(const char **path_r, void *context) +{ + struct mail_user *user = context; + string_t *path; + int fd; + + path = t_str_new(128); + str_append(path, mail_user_get_temp_prefix(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(const char *temp_path_prefix, int fd, time_t *mtime_r) +create_raw_stream(struct mail_user *user, int fd, time_t *mtime_r) { struct istream *input, *input2, *input_list[2]; const unsigned char *data; @@ -661,7 +688,7 @@ 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, user); i_stream_unref(&input2); return input; } @@ -1115,8 +1142,7 @@ FILE_LOCK_METHOD_FCNTL, &errstr) < 0) i_fatal("Couldn't create internal raw storage: %s", errstr); if (path == NULL) { - const char *prefix = mail_user_get_temp_prefix(mail_user); - input = create_raw_stream(prefix, 0, &mtime); + input = create_raw_stream(mail_user, 0, &mtime); box = mailbox_open(&raw_ns->storage, "Dovecot Delivery Mail", input, MAILBOX_OPEN_NO_INDEX_FILES); i_stream_unref(&input); diff -r 616c0ee81222 -r 82949209612e src/lib/istream-seekable.c --- a/src/lib/istream-seekable.c Mon May 25 21:53:13 2009 -0400 +++ b/src/lib/istream-seekable.c Mon May 25 22:18:55 2009 -0400 @@ -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 -#include -#include -#include - #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 @@ 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 @@ 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 = sstream->fd_callback(&path, sstream->context); + if (fd == -1) + 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); - 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 @@ 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 @@ 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_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; diff -r 616c0ee81222 -r 82949209612e src/lib/istream-seekable.h --- a/src/lib/istream-seekable.h Mon May 25 21:53:13 2009 -0400 +++ b/src/lib/istream-seekable.h Mon May 25 22:18:55 2009 -0400 @@ -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