[dovecot-cvs] dovecot/src/lib istream-mmap.c,1.4,1.5 istream.h,1.5,1.6 ostream-file.c,1.9,1.10 ostream.h,1.5,1.6
cras at procontrol.fi
cras at procontrol.fi
Wed Feb 19 21:50:25 EET 2003
Update of /home/cvs/dovecot/src/lib
In directory danu:/tmp/cvs-serv16376
Modified Files:
istream-mmap.c istream.h ostream-file.c ostream.h
Log Message:
o_stream_send_istream() is now safe to use for moving data within file.
Index: istream-mmap.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream-mmap.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- istream-mmap.c 11 Feb 2003 16:37:47 -0000 1.4
+++ istream-mmap.c 19 Feb 2003 19:50:22 -0000 1.5
@@ -80,7 +80,14 @@
{
struct mmap_istream *mstream = (struct mmap_istream *) stream;
- mstream->mmap_block_size = max_size;
+ /* allow only full page sizes */
+ if (max_size < mmap_pagesize)
+ mstream->mmap_block_size = mmap_pagesize;
+ else {
+ if (max_size % mmap_pagesize != 0)
+ max_size += mmap_pagesize - (max_size % mmap_pagesize);
+ mstream->mmap_block_size = max_size;
+ }
}
static void _set_blocking(struct _iostream *stream __attr_unused__,
@@ -205,6 +212,7 @@
int autoclose_fd)
{
struct mmap_istream *mstream;
+ struct istream *istream;
struct stat st;
if (mmap_pagesize == 0) {
@@ -226,7 +234,7 @@
mstream = p_new(pool, struct mmap_istream, 1);
mstream->fd = fd;
- mstream->mmap_block_size = block_size;
+ _set_max_buffer_size(&mstream->istream.iostream, block_size);
mstream->autoclose_fd = autoclose_fd;
mstream->istream.iostream.close = _close;
@@ -238,6 +246,8 @@
mstream->istream.skip_count = _skip;
mstream->istream.seek = _seek;
- return _i_stream_create(&mstream->istream, pool, fd,
- start_offset, v_size);
+ istream = _i_stream_create(&mstream->istream, pool, fd,
+ start_offset, v_size);
+ istream->mmaped = TRUE;
+ return istream;
}
Index: istream.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/istream.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- istream.h 23 Jan 2003 19:08:53 -0000 1.5
+++ istream.h 19 Feb 2003 19:50:22 -0000 1.6
@@ -6,6 +6,7 @@
uoff_t v_offset, v_size, v_limit; /* relative to start_offset */
int stream_errno;
+ unsigned int mmaped:1; /* be careful when copying data */
unsigned int closed:1;
struct _istream *real_stream;
Index: ostream-file.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib/ostream-file.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- ostream-file.c 11 Feb 2003 16:37:47 -0000 1.9
+++ ostream-file.c 19 Feb 2003 19:50:22 -0000 1.10
@@ -28,9 +28,12 @@
#include "lib.h"
#include "alarm-hup.h"
#include "ioloop.h"
+#include "file-set-size.h"
+#include "write-full.h"
#include "network.h"
#include "sendfile-util.h"
#include "istream.h"
+#include "istream-internal.h"
#include "ostream-internal.h"
#include <unistd.h>
@@ -505,21 +508,15 @@
}
}
-static int io_stream_sendfile(struct _ostream *outstream,
- struct istream *instream)
+static off_t io_stream_sendfile(struct _ostream *outstream,
+ struct istream *instream, int in_fd)
{
struct file_ostream *foutstream = (struct file_ostream *) outstream;
time_t timeout_time;
uoff_t start_offset;
uoff_t offset, send_size, v_offset;
ssize_t ret;
- int in_fd, first;
-
- in_fd = i_stream_get_fd(instream);
- if (in_fd == -1) {
- outstream->ostream.stream_errno = EINVAL;
- return -1;
- }
+ int first;
/* set timeout time before flushing existing buffer which may block */
timeout_time = GET_TIMEOUT_TIME(foutstream);
@@ -574,11 +571,11 @@
} while ((uoff_t)ret != send_size);
i_stream_seek(instream, instream->start_offset + v_offset);
- return ret < 0 ? -1 : 0;
+ return ret < 0 ? -1 : (off_t)(instream->v_offset - start_offset);
}
static off_t io_stream_copy(struct _ostream *outstream,
- struct istream *instream)
+ struct istream *instream, int overlapping)
{
struct file_ostream *foutstream = (struct file_ostream *) outstream;
time_t timeout_time;
@@ -593,8 +590,12 @@
timeout_time = GET_TIMEOUT_TIME(foutstream);
iov_len = o_stream_fill_iovec(foutstream, iov);
+ i_assert(!overlapping || iov_len == 0);
+
start_offset = instream->v_offset;
for (;;) {
+ if (overlapping)
+ i_stream_seek(instream, instream->v_offset);
(void)i_stream_read_data(instream, &data, &size,
O_STREAM_MIN_SIZE-1);
@@ -607,6 +608,12 @@
iov[pos].iov_base = (void *) data;
iov[pos].iov_len = size;
+ if (overlapping) {
+ if (o_stream_seek(&outstream->ostream,
+ outstream->ostream.offset) < 0)
+ return -1;
+ }
+
ret = o_stream_writev(foutstream, iov, iov_len);
if (ret < 0) {
/* error */
@@ -643,10 +650,102 @@
return (off_t) (instream->v_offset - start_offset);
}
+static off_t io_stream_copy_backwards(struct _ostream *outstream,
+ struct istream *instream)
+{
+ struct file_ostream *foutstream = (struct file_ostream *) outstream;
+ time_t timeout_time;
+ uoff_t in_start_offset, in_offset, out_offset;
+ const unsigned char *data;
+ unsigned char buffer[4096];
+ size_t buffer_size, size, read_size;
+ ssize_t ret;
+
+ i_assert(IS_STREAM_EMPTY(foutstream));
+
+ timeout_time = GET_TIMEOUT_TIME(foutstream);
+
+ buffer_size = instream->real_stream->buffer_size;
+ if (buffer_size == 0 || buffer_size > sizeof(buffer))
+ buffer_size = sizeof(buffer);
+
+ in_start_offset = instream->v_offset;
+ in_offset = instream->v_limit;
+ out_offset = outstream->ostream.offset +
+ (instream->v_limit - instream->v_offset);
+
+ i_assert(out_offset <= instream->start_offset + instream->v_size);
+
+ while (in_offset > in_start_offset) {
+ if (in_offset - in_start_offset <= buffer_size)
+ read_size = in_offset - in_start_offset;
+ else
+ read_size = buffer_size;
+ in_offset -= read_size;
+ out_offset -= read_size;
+
+ for (;;) {
+ i_assert(in_offset <= instream->v_limit);
+
+ i_stream_seek(instream, in_offset);
+ read_size = instream->v_limit - in_offset;
+
+ (void)i_stream_read_data(instream, &data, &size,
+ read_size-1);
+ if (size == read_size) {
+ if (instream->mmaped) {
+ /* we'll have to write it through
+ buffer of the file gets corrupted */
+ i_assert(size <= sizeof(buffer));
+ memcpy(buffer, data, size);
+ data = buffer;
+ }
+ break;
+ }
+
+ i_assert(size < read_size);
+ if (size < read_size) {
+ /* buffer too large probably,
+ try with smaller */
+ read_size -= size;
+ in_offset += read_size;
+ out_offset += read_size;
+ buffer_size -= read_size;
+ }
+ }
+
+ if (o_stream_seek(&outstream->ostream, out_offset) < 0)
+ return -1;
+
+ ret = write_full(foutstream->fd, data, size);
+ if (ret < 0) {
+ /* error */
+ outstream->ostream.stream_errno = errno;
+ return -1;
+ }
+
+ if (timeout_time > 0 && time(NULL) > timeout_time) {
+ /* timeouted */
+ if (foutstream->timeout_cb != NULL) {
+ foutstream->timeout_cb(
+ foutstream->timeout_context);
+ }
+ outstream->ostream.stream_errno = EAGAIN;
+ return -1;
+ }
+
+ i_stream_set_read_limit(instream, in_offset);
+ }
+
+ return (off_t) (instream->v_limit - in_start_offset);
+}
+
static off_t _send_istream(struct _ostream *outstream, struct istream *instream)
{
struct file_ostream *foutstream = (struct file_ostream *) outstream;
+ uoff_t old_limit;
off_t ret;
+ int in_fd, overlapping;
i_assert(instream->v_limit <= OFF_T_MAX);
i_assert(instream->v_offset <= instream->v_limit);
@@ -656,8 +755,28 @@
if (instream->v_offset == instream->v_limit)
return 0;
- if (!foutstream->no_sendfile) {
- ret = io_stream_sendfile(outstream, instream);
+ in_fd = i_stream_get_fd(instream);
+ if (in_fd != foutstream->fd)
+ overlapping = 0;
+ else {
+ /* copying data within same fd. we'll have to be careful with
+ seeks and overlapping writes. */
+ ret = (off_t)outstream->ostream.offset -
+ (off_t)(instream->start_offset + instream->v_offset);
+ if (ret == 0) {
+ /* copying data over itself. we don't really
+ need to do that, just fake it. */
+ return instream->v_limit - instream->v_offset;
+ }
+ overlapping = ret < 0 ? -1 : 1;
+
+ if (o_stream_seek(&outstream->ostream,
+ outstream->ostream.offset) < 0)
+ return -1;
+ }
+
+ if (!foutstream->no_sendfile && in_fd != -1 && overlapping <= 0) {
+ ret = io_stream_sendfile(outstream, instream, in_fd);
if (ret >= 0 || outstream->ostream.stream_errno != EINVAL)
return ret;
@@ -667,7 +786,14 @@
foutstream->no_sendfile = TRUE;
}
- return io_stream_copy(outstream, instream);
+ if (overlapping <= 0)
+ return io_stream_copy(outstream, instream, overlapping);
+ else {
+ old_limit = instream->v_limit;
+ ret = io_stream_copy_backwards(outstream, instream);
+ i_stream_set_read_limit(instream, old_limit);
+ return ret;
+ }
}
struct ostream *
Index: ostream.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib/ostream.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- ostream.h 23 Jan 2003 19:08:53 -0000 1.5
+++ ostream.h 19 Feb 2003 19:50:22 -0000 1.6
@@ -49,7 +49,11 @@
ssize_t o_stream_send_str(struct ostream *stream, const char *str);
/* Send data from input stream. Returns number of bytes sent, or -1 if error.
Note that this function may block if either instream or outstream is
- blocking. */
+ blocking.
+
+ It's also possible to use this function to copy data within same file
+ descriptor. If the file must be grown, you have to do it manually before
+ calling this function. */
off_t o_stream_send_istream(struct ostream *outstream,
struct istream *instream);
More information about the dovecot-cvs
mailing list