view src/lib-storage/index/index-save.c @ 903:fd8888f6f037 HEAD

Naming style changes, finally got tired of most of the typedefs. Also the previous enum -> macro change reverted so that we don't use the highest bit anymore, that's incompatible with old indexes so they will be rebuilt.
author Timo Sirainen <tss@iki.fi>
date Sun, 05 Jan 2003 15:09:51 +0200
parents f57c52738f90
children 40a327d356de
line wrap: on
line source

/* Copyright (C) 2002 Timo Sirainen */

#include "lib.h"
#include "istream.h"
#include "ostream.h"
#include "write-full.h"
#include "index-storage.h"

#include <stdlib.h>
#include <unistd.h>

static int write_with_crlf(struct ostream *output, const unsigned char *data,
			   size_t size)
{
	size_t i, start;

	i_assert(size > 0 && size <= SSIZE_T_MAX);

	start = 0;
	for (i = 0; i < size; i++) {
		if (data[i] == '\n' && (i == 0 || data[i-1] != '\r')) {
			/* missing CR */
			if (o_stream_send(output, data + start, i - start) < 0)
				return -1;
			if (o_stream_send(output, "\r", 1) < 0)
				return -1;

			/* \n is written next time */
			start = i;
		}
	}

	/* if last char is \r, leave it to buffer */
	if (data[size-1] == '\r')
		size--;

	if (o_stream_send(output, data + start, size - start) < 0)
		return -1;

	return size;
}

static int write_with_lf(struct ostream *output, const unsigned char *data,
			 size_t size)
{
	size_t i, start;

	i_assert(size > 0 && size <= SSIZE_T_MAX);

	start = 0;
	for (i = 0; i < size; i++) {
		if (data[i] == '\n' && i > 0 && data[i-1] == '\r') {
			/* \r\n - skip \r */
			if (o_stream_send(output, data + start,
					   i - start - 1) < 0)
				return -1;

			/* \n is written next time */
			start = i;
		}
	}

	/* if last char is \r, leave it to buffer */
	if (data[size-1] == '\r')
		size--;

	if (o_stream_send(output, data + start, size - start) < 0)
		return -1;

	return size;
}

int index_storage_save(struct mail_storage *storage, const char *path,
		       struct istream *input, struct ostream *output,
		       uoff_t data_size)
{
	int (*write_func)(struct ostream *, const unsigned char *, size_t);
	const unsigned char *data;
	size_t size;
	ssize_t ret;
	int failed;

	write_func = getenv("MAIL_SAVE_CRLF") ? write_with_crlf : write_with_lf;

	failed = FALSE;
	while (data_size > 0) {
		ret = i_stream_read(input);
		if (ret < 0) {
			errno = input->stream_errno;
			if (errno == 0) {
				mail_storage_set_error(storage,
					"Client disconnected");
			} else if (errno == EAGAIN) {
				mail_storage_set_error(storage,
					"Timeout while waiting for input");
			} else {
				mail_storage_set_critical(storage,
					"Error reading mail from client: %m");
			}
			return FALSE;
		}

		data = i_stream_get_data(input, &size);
		if (size > data_size)
			size = (size_t)data_size;

		if (!failed) {
			ret = write_func(output, data, size);
			if (ret < 0) {
				errno = output->stream_errno;
				if (errno == ENOSPC) {
					mail_storage_set_error(storage,
						"Not enough disk space");
				} else {
					mail_storage_set_critical(storage,
						"write_full() failed for file "
						"%s: %m", path);
				}
				failed = TRUE;
			} else {
				size = ret;
			}
		}

		data_size -= size;
		i_stream_skip(input, size);
	}

	return !failed;
}