dovecot-2.2: Added iostream-temp for easily creating a temporary...
dovecot at dovecot.org
dovecot at dovecot.org
Mon Nov 26 23:08:17 EET 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/faa3a83282fb
changeset: 15402:faa3a83282fb
user: Timo Sirainen <tss at iki.fi>
date: Mon Nov 26 23:08:10 2012 +0200
description:
Added iostream-temp for easily creating a temporary istream (to memory/file).
diffstat:
src/lib/Makefile.am | 2 +
src/lib/iostream-temp.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++
src/lib/iostream-temp.h | 12 +++
3 files changed, 163 insertions(+), 0 deletions(-)
diffs (188 lines):
diff -r 22cfb7b347a8 -r faa3a83282fb src/lib/Makefile.am
--- a/src/lib/Makefile.am Mon Nov 26 23:06:24 2012 +0200
+++ b/src/lib/Makefile.am Mon Nov 26 23:08:10 2012 +0200
@@ -52,6 +52,7 @@
ipwd.c \
iostream.c \
iostream-rawlog.c \
+ iostream-temp.c \
iso8601-date.c \
istream.c \
istream-base64-decoder.c \
@@ -179,6 +180,7 @@
iostream-private.h \
iostream-rawlog.h \
iostream-rawlog-private.h \
+ iostream-temp.h \
iso8601-date.h \
istream.h \
istream-base64.h \
diff -r 22cfb7b347a8 -r faa3a83282fb src/lib/iostream-temp.c
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/iostream-temp.c Mon Nov 26 23:08:10 2012 +0200
@@ -0,0 +1,149 @@
+/* Copyright (c) 2012 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "str.h"
+#include "safe-mkstemp.h"
+#include "write-full.h"
+#include "istream.h"
+#include "ostream-private.h"
+#include "iostream-temp.h"
+
+#include <unistd.h>
+
+#define IOSTREAM_TEMP_MAX_BUF_SIZE (1024*128)
+
+struct temp_ostream {
+ struct ostream_private ostream;
+ char *temp_path_prefix;
+ buffer_t *buf;
+ int fd;
+ bool fd_tried;
+};
+
+static void o_stream_temp_close(struct iostream_private *stream)
+{
+ struct temp_ostream *tstream = (struct temp_ostream *)stream;
+
+ if (tstream->fd != -1)
+ i_close_fd(&tstream->fd);
+ if (tstream->buf != NULL)
+ buffer_free(&tstream->buf);
+ i_free(tstream->temp_path_prefix);
+}
+
+static int o_stream_temp_move_to_fd(struct temp_ostream *tstream)
+{
+ string_t *path;
+
+ if (tstream->fd_tried)
+ return -1;
+ tstream->fd_tried = TRUE;
+
+ path = t_str_new(128);
+ str_append(path, tstream->temp_path_prefix);
+ tstream->fd = safe_mkstemp_hostpid(path, 0600, (uid_t)-1, (gid_t)-1);
+ if (tstream->fd == -1) {
+ i_error("safe_mkstemp(%s) failed: %m", str_c(path));
+ return -1;
+ }
+ if (unlink(str_c(path)) < 0) {
+ i_error("unlink(%s) failed: %m", str_c(path));
+ i_close_fd(&tstream->fd);
+ return -1;
+ }
+ if (write_full(tstream->fd, tstream->buf->data, tstream->buf->used) < 0) {
+ i_error("write(%s) failed: %m", str_c(path));
+ i_close_fd(&tstream->fd);
+ return -1;
+ }
+ buffer_free(&tstream->buf);
+ return 0;
+}
+
+static ssize_t
+o_stream_temp_fd_sendv(struct temp_ostream *tstream,
+ const struct const_iovec *iov, unsigned int iov_count)
+{
+ size_t bytes = 0;
+ unsigned int i;
+
+ for (i = 0; i < iov_count; i++) {
+ if (write_full(tstream->fd, iov[i].iov_base, iov[i].iov_len) < 0) {
+ tstream->ostream.ostream.stream_errno = errno;
+ return -1;
+ }
+ bytes += iov[i].iov_len;
+ tstream->ostream.ostream.offset += iov[i].iov_len;
+ }
+ return bytes;
+}
+
+static ssize_t
+o_stream_temp_sendv(struct ostream_private *stream,
+ const struct const_iovec *iov, unsigned int iov_count)
+{
+ struct temp_ostream *tstream = (struct temp_ostream *)stream;
+ ssize_t ret = 0;
+ unsigned int i;
+
+ if (tstream->fd != -1)
+ return o_stream_temp_fd_sendv(tstream, iov, iov_count);
+
+ for (i = 0; i < iov_count; i++) {
+ if (tstream->buf->used + iov[i].iov_len > IOSTREAM_TEMP_MAX_BUF_SIZE) {
+ if (o_stream_temp_move_to_fd(tstream) == 0) {
+ return o_stream_temp_fd_sendv(tstream, iov+i,
+ iov_count-i);
+ }
+ /* failed to move to temp fd, just keep it in memory */
+ }
+ buffer_append(tstream->buf, iov[i].iov_base, iov[i].iov_len);
+ ret += iov[i].iov_len;
+ stream->ostream.offset += iov[i].iov_len;
+ }
+ return ret;
+}
+
+struct ostream *iostream_temp_create(const char *temp_path_prefix)
+{
+ struct temp_ostream *tstream;
+ struct ostream *output;
+
+ tstream = i_new(struct temp_ostream, 1);
+ tstream->ostream.sendv = o_stream_temp_sendv;
+ tstream->ostream.iostream.close = o_stream_temp_close;
+ tstream->temp_path_prefix = i_strdup(temp_path_prefix);
+ tstream->buf = buffer_create_dynamic(default_pool, 8192);
+ tstream->fd = -1;
+
+ output = o_stream_create(&tstream->ostream, NULL, -1);
+ o_stream_set_name(output, "(temp iostream)");
+ return output;
+}
+
+static void iostream_temp_buf_destroyed(buffer_t *buf)
+{
+ buffer_free(&buf);
+}
+
+struct istream *iostream_temp_finish(struct ostream **output,
+ size_t max_buffer_size)
+{
+ struct temp_ostream *tstream =
+ (struct temp_ostream *)(*output)->real_stream;
+ struct istream *input;
+
+ if (tstream->fd != -1) {
+ input = i_stream_create_fd(tstream->fd, max_buffer_size, TRUE);
+ tstream->fd = -1;
+ } else {
+ input = i_stream_create_from_data(tstream->buf->data,
+ tstream->buf->used);
+ i_stream_set_destroy_callback(input, iostream_temp_buf_destroyed,
+ tstream->buf);
+ tstream->buf = NULL;
+ }
+ o_stream_destroy(output);
+ return input;
+}
diff -r 22cfb7b347a8 -r faa3a83282fb src/lib/iostream-temp.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib/iostream-temp.h Mon Nov 26 23:08:10 2012 +0200
@@ -0,0 +1,12 @@
+#ifndef IOSTREAM_TEMP_H
+#define IOSTREAM_TEMP_H
+
+/* Start writing to given output stream. The data is initially written to
+ memory, and later to a temporary file that is immediately unlinked. */
+struct ostream *iostream_temp_create(const char *temp_path_prefix);
+/* Finished writing to stream. Return input stream for it and free the
+ output stream. */
+struct istream *iostream_temp_finish(struct ostream **output,
+ size_t max_buffer_size);
+
+#endif
More information about the dovecot-cvs
mailing list