<commit_before>/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "buffer.h"
#include "close-keep-errno.h"
#include "read-full.h"
#include "write-full.h"
#include "istream-internal.h"
#include "istream-concat.h"
#include "istream-seekable.h"

#include <unistd.h>

#define BUF_INITIAL_SIZE (1024*32)

struct seekable_istream {
	struct istream_private istream;

	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;
	unsigned int cur_idx;
	int fd;
};

static void i_stream_seekable_close(struct iostream_private *stream)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	unsigned int i;

	sstream->fd = -1;
	if (sstream->fd_input != NULL)
		i_stream_close(sstream->fd_input);
	for (i = 0; sstream->input[i] != NULL; i++)
		i_stream_close(sstream->input[i]);
}

static void i_stream_seekable_destroy(struct iostream_private *stream)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	unsigned int i;

	if (sstream->buffer != NULL)
		buffer_free(&sstream->buffer);
	if (sstream->fd_input != NULL)
		i_stream_unref(&sstream->fd_input);
	for (i = 0; sstream->input[i] != NULL; i++)
		i_stream_unref(&sstream->input[i]);

	i_free(sstream->temp_path);
}

static void
i_stream_seekable_set_max_buffer_size(struct iostream_private *stream,
				      size_t max_size)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	unsigned int i;

	sstream->istream.max_buffer_size = max_size;
	if (sstream->fd_input != NULL)
		i_stream_set_max_buffer_size(sstream->fd_input, max_size);
	for (i = 0; sstream->input[i] != NULL; i++)
		i_stream_set_max_buffer_size(sstream->input[i], max_size);
}

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->buffer->data, sstream->buffer->used) < 0) {
		if (!ENOSPACE(errno))
			i_error("write_full(%s) failed: %m", path);
		close_keep_errno(fd);
		return -1;
	}
	sstream->temp_path = i_strdup(path);
	sstream->write_peak = sstream->buffer->used;

	sstream->fd = fd;
	sstream->fd_input =
		i_stream_create_fd(fd, sstream->istream.max_buffer_size, TRUE);

	/* 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->buffer);
	return 0;
}

static ssize_t read_more(struct seekable_istream *sstream)
{
	size_t size;
	ssize_t ret;

	if (sstream->cur_input == NULL) {
		sstream->istream.istream.eof = TRUE;
		return -1;
	}

	while ((ret = i_stream_read(sstream->cur_input)) < 0) {
		if (!sstream->cur_input->eof) {
			/* full / error */
			sstream->istream.istream.stream_errno =
				sstream->cur_input->stream_errno;
			return ret;
		}

		/* go to next stream */
		sstream->cur_input = sstream->input[sstream->cur_idx++];
		if (sstream->cur_input == NULL) {
			/* last one, EOF */
			sstream->istream.istream.eof = TRUE;
			return -1;
		}

		/* see if stream has pending data */
		(void)i_stream_get_data(sstream->cur_input, &size);
		if (size != 0)<commit_msg>istream-seekable: Minor code cleanup.<commit_after>/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */

#include "lib.h"
#include "buffer.h"
#include "close-keep-errno.h"
#include "read-full.h"
#include "write-full.h"
#include "istream-internal.h"
#include "istream-concat.h"
#include "istream-seekable.h"

#include <unistd.h>

#define BUF_INITIAL_SIZE (1024*32)

struct seekable_istream {
	struct istream_private istream;

	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;
	unsigned int cur_idx;
	int fd;
};

static void i_stream_seekable_close(struct iostream_private *stream)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	unsigned int i;

	sstream->fd = -1;
	if (sstream->fd_input != NULL)
		i_stream_close(sstream->fd_input);
	for (i = 0; sstream->input[i] != NULL; i++)
		i_stream_close(sstream->input[i]);
}

static void i_stream_seekable_destroy(struct iostream_private *stream)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	unsigned int i;

	if (sstream->buffer != NULL)
		buffer_free(&sstream->buffer);
	if (sstream->fd_input != NULL)
		i_stream_unref(&sstream->fd_input);
	for (i = 0; sstream->input[i] != NULL; i++)
		i_stream_unref(&sstream->input[i]);

	i_free(sstream->temp_path);
}

static void
i_stream_seekable_set_max_buffer_size(struct iostream_private *stream,
				      size_t max_size)
{
	struct seekable_istream *sstream = (struct seekable_istream *)stream;
	unsigned int i;

	sstream->istream.max_buffer_size = max_size;
	if (sstream->fd_input != NULL)
		i_stream_set_max_buffer_size(sstream->fd_input, max_size);
	for (i = 0; sstream->input[i] != NULL; i++)
		i_stream_set_max_buffer_size(sstream->input[i], max_size);
}

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->buffer->data, sstream->buffer->used) < 0) {
		if (!ENOSPACE(errno))
			i_error("write_full(%s) failed: %m", path);
		close_keep_errno(fd);
		return -1;
	}
	sstream->temp_path = i_strdup(path);
	sstream->write_peak = sstream->buffer->used;

	sstream->fd = fd;
	sstream->fd_input =
		i_stream_create_fd(fd, sstream->istream.max_buffer_size, TRUE);

	/* 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->buffer);
	return 0;
}

static ssize_t read_more(struct seekable_istream *sstream)
{
	size_t size;
	ssize_t ret;

	if (sstream->cur_input == NULL) {
		sstream->istream.istream.eof = TRUE;
		return -1;
	}

	while ((ret = i_stream_read(sstream->cur_input)) < 0) {
		if (!sstream->cur_input->eof) {
			/* full / error */
			sstream->istream.istream.stream_errno =
				sstream->cur_input->stream_errno;
			return -1;
		}

		/* go to next stream */
		sstream->cur_input = sstream->input[sstream->cur_idx++];
		if (sstream->cur_input == NULL) {
			/* last one, EOF */
			sstream->istream.istream.eof = TRUE;
			return -1;
		}

		/* see if stream has pending data */
		(void)i_stream_get_data(sstream->cur_input, &size);
		if (size != 0)
{'fraction_non_alphanumeric': 0.14546889385768774, 'fraction_numerical': 0.007760094699460739, 'mean_word_length': 4.611808118081181, 'pattern_counts': {'":': 0, '<': 11, '<?xml version=': 0, '>': 117, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3485929', 'n_tokens_mistral': 3094, 'n_tokens_neox': 2894, 'n_words': 614}