static int maildir_sync_flags(struct maildir_mailbox *mbox, const char *path,
			      struct maildir_index_sync_context *ctx)
{
	struct mailbox *box = &mbox->box;
	struct stat st;
	const char *dir, *fname, *newfname, *newpath;
	enum mail_index_sync_type sync_type;
	uint8_t flags8;

	ctx->flag_change_count++;

	fname = strrchr(path, '/');
	i_assert(fname != NULL);
	fname++;
	dir = t_strdup_until(path, fname);

	i_assert(*fname != '\0');

	/* get the current flags and keywords */
	maildir_filename_flags_get(ctx->keywords_sync_ctx,
				   fname, &ctx->flags, &ctx->keywords);

	/* apply changes */
	flags8 = ctx->flags;
	index_sync_changes_apply(ctx->sync_changes, NULL,
				 &flags8, &ctx->keywords, &sync_type);
	ctx->flags = flags8;

	/* and try renaming with the new name */
	newfname = maildir_filename_flags_kw_set(ctx->keywords_sync_ctx, fname,
						 ctx->flags, &ctx->keywords);
	newpath = t_strconcat(dir, newfname, NULL);
	if (strcmp(path, newpath) == 0) {
		/* just make sure that the file still exists. avoid rename()
		   here because it's slow on HFS. */
		if (stat(path, &st) < 0) {
			if (errno == ENOENT)
				return 0;
			mail_storage_set_critical(box->storage,
				"stat(%s) failed: %m", path);
			return -1;
		}
	} else {
		if (rename(path, newpath) < 0) {
			if (errno == ENOENT)
				return 0;
			if (!ENOSPACE(errno) && errno != EACCES) {
				mail_storage_set_critical(box->storage,
					"rename(%s, %s) failed: %m",
					path, newpath);
			}
			return -1;
		}
	}
	if (box->v.sync_notify != NULL) {
		box->v.sync_notify(box, ctx->uid,
				   index_sync_type_convert(sync_type));
	}
	return 1;
}
Exemple #2
0
static int copy_to_temp_file(struct seekable_istream *sstream)
{
	struct istream_private *stream = &sstream->istream;
	const char *path;
	const unsigned char *buffer;
	size_t size;
	int fd;

	fd = sstream->fd_callback(&path, sstream->context);
	if (fd == -1)
		return -1;

	/* copy our currently read buffer to it */
	i_assert(stream->pos <= sstream->buffer_peak);
	if (write_full(fd, stream->buffer, sstream->buffer_peak) < 0) {
		if (!ENOSPACE(errno))
			i_error("istream-seekable: write_full(%s) failed: %m", path);
		i_close_fd(&fd);
		return -1;
	}
	sstream->temp_path = i_strdup(path);
	sstream->write_peak = sstream->buffer_peak;

	sstream->fd = fd;
	sstream->fd_input = i_stream_create_fd_autoclose(&fd,
		I_MAX(stream->pos, sstream->istream.max_buffer_size));
	i_stream_set_name(sstream->fd_input, t_strdup_printf(
		"(seekable temp-istream for: %s)", i_stream_get_name(&stream->istream)));

	/* read back the data we just had in our buffer */
	for (;;) {
		buffer = i_stream_get_data(sstream->fd_input, &size);
		if (size >= stream->pos)
			break;

		ssize_t ret;
		if ((ret = i_stream_read_memarea(sstream->fd_input)) <= 0) {
			i_assert(ret != 0);
			i_assert(ret != -2);
			i_error("istream-seekable: Couldn't read back "
				"in-memory input %s: %s",
				i_stream_get_name(&stream->istream),
				i_stream_get_error(sstream->fd_input));
			i_stream_destroy(&sstream->fd_input);
			i_close_fd(&sstream->fd);
			return -1;
		}
	}
	/* Set the max buffer size only after we've already read everything
	   into memory. For example with istream-data it's possible that
	   more data exists in buffer than max_buffer_size. */
	i_stream_set_max_buffer_size(sstream->fd_input,
				     sstream->istream.max_buffer_size);
	stream->buffer = buffer;
	i_stream_free_buffer(&sstream->istream);
	return 0;
}
void mbox_set_syscall_error(struct mbox_mailbox *mbox, const char *function)
{
	i_assert(function != NULL);

	if (ENOSPACE(errno)) {
		mail_storage_set_error(&mbox->storage->storage,
			MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
	} else {
		const char *toobig_error = errno != EFBIG ? "" :
			" (process was started with ulimit -f limit)";
		mail_storage_set_critical(&mbox->storage->storage,
			"%s failed with mbox file %s: %m%s", function,
			mailbox_get_path(&mbox->box), toobig_error);
	}
}
static int copy_to_temp_file(struct seekable_istream *sstream)
{
    struct istream_private *stream = &sstream->istream;
    const char *path;
    const unsigned char *buffer;
    size_t size;
    int fd;

    fd = sstream->fd_callback(&path, sstream->context);
    if (fd == -1)
        return -1;

    /* copy our currently read buffer to it */
    if (write_full(fd, sstream->membuf->data, sstream->membuf->used) < 0) {
        if (!ENOSPACE(errno))
            i_error("istream-seekable: write_full(%s) failed: %m", path);
        i_close_fd(&fd);
        return -1;
    }
    sstream->temp_path = i_strdup(path);
    sstream->write_peak = sstream->membuf->used;

    sstream->fd = fd;
    sstream->fd_input =
        i_stream_create_fd_autoclose(&fd, sstream->istream.max_buffer_size);
    i_stream_set_name(sstream->fd_input, t_strdup_printf(
                          "(seekable temp-istream for: %s)", i_stream_get_name(&stream->istream)));

    /* read back the data we just had in our buffer */
    i_stream_seek(sstream->fd_input, stream->istream.v_offset);
    for (;;) {
        buffer = i_stream_get_data(sstream->fd_input, &size);
        if (size >= stream->pos)
            break;

        if (i_stream_read(sstream->fd_input) <= 0) {
            i_error("istream-seekable: Couldn't read back "
                    "in-memory input %s",
                    i_stream_get_name(&stream->istream));
            i_stream_destroy(&sstream->fd_input);
            return -1;
        }
    }
    stream->buffer = buffer;
    stream->pos = size;
    buffer_free(&sstream->membuf);
    return 0;
}
Exemple #5
0
static ssize_t i_stream_seekable_read(struct istream_private *stream)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	const unsigned char *data;
	size_t size, pos;
	ssize_t ret;

	if (sstream->fd == -1) {
		if (read_from_buffer(sstream, &ret))
			return ret;

		/* copy everything to temp file and use it as the stream */
		if (copy_to_temp_file(sstream) < 0) {
			stream->max_buffer_size = (size_t)-1;
			if (!read_from_buffer(sstream, &ret))
				i_unreached();
			return ret;
		}
		i_assert(sstream->fd != -1);
	}

	stream->buffer = CONST_PTR_OFFSET(stream->buffer, stream->skip);
	stream->pos -= stream->skip;
	stream->skip = 0;

	i_assert(stream->istream.v_offset + stream->pos <= sstream->write_peak);
	if (stream->istream.v_offset + stream->pos == sstream->write_peak) {
		/* need to read more */
		if (sstream->cur_input == NULL ||
		    i_stream_get_data_size(sstream->cur_input) == 0) {
			ret = read_more(sstream);
			if (ret == -1 || ret == 0)
				return ret;
		}

		/* save to our file */
		data = i_stream_get_data(sstream->cur_input, &size);
		ret = write(sstream->fd, data, size);
		if (ret <= 0) {
			if (ret < 0 && !ENOSPACE(errno)) {
				i_error("istream-seekable: write_full(%s) failed: %m",
					sstream->temp_path);
			}
			if (i_stream_seekable_write_failed(sstream) < 0)
				return -1;
			if (!read_from_buffer(sstream, &ret))
				i_unreached();
			return ret;
		}
		i_stream_sync(sstream->fd_input);
		i_stream_skip(sstream->cur_input, ret);
		sstream->write_peak += ret;
	}

	i_stream_seek(sstream->fd_input, stream->istream.v_offset);
	ret = i_stream_read_memarea(sstream->fd_input);
	if (ret <= 0) {
		stream->istream.eof = sstream->fd_input->eof;
		stream->istream.stream_errno =
			sstream->fd_input->stream_errno;
	} else {
		ret = -2;
	}

	stream->buffer = i_stream_get_data(sstream->fd_input, &pos);
	stream->pos -= stream->skip;
	stream->skip = 0;

	ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : ret;
	stream->pos = pos;
	return ret;
}
Exemple #6
0
int file_set_size(int fd, off_t size)
{
#ifdef HAVE_POSIX_FALLOCATE
	static bool posix_fallocate_supported = TRUE;
#endif
	char block[IO_BLOCK_SIZE];
	off_t offset;
	ssize_t ret;
	struct stat st;

	i_assert(size >= 0);

	if (fstat(fd, &st) < 0) {
		i_error("fstat() failed: %m");
		return -1;
	}

	if (size < st.st_size) {
		if (ftruncate(fd, size) < 0) {
			i_error("ftruncate() failed: %m");
			return -1;
		}
		return 0;
	}
	if (size == st.st_size)
		return 0;

#ifdef HAVE_POSIX_FALLOCATE
	if (posix_fallocate_supported) {
		int err;

		err = posix_fallocate(fd, st.st_size, size - st.st_size);
		if (err == 0)
			return 0;

		if (err != EINVAL /* Solaris */ &&
		    err != EOPNOTSUPP /* AOX */) {
			if (!ENOSPACE(err))
				i_error("posix_fallocate() failed: %m");
			return -1;
		}
		/* Not supported by kernel, fallback to writing. */
		posix_fallocate_supported = FALSE;
	}
#endif
	/* start growing the file */
	offset = st.st_size;
	memset(block, 0, I_MIN((ssize_t)sizeof(block), size - offset));

	while (offset < size) {
		ret = pwrite(fd, block,
			     I_MIN((ssize_t)sizeof(block), size - offset),
			     offset);
		if (ret < 0) {
			if (!ENOSPACE(errno))
				i_error("pwrite() failed: %m");
			return -1;
		}
		offset += ret;
	}
	return 0;
}