ssize_t i_stream_read_copy_from_parent(struct istream *istream) { struct istream_private *stream = istream->real_stream; size_t pos; ssize_t ret; stream->pos -= stream->skip; stream->skip = 0; stream->buffer = i_stream_get_data(stream->parent, &pos); if (pos > stream->pos) ret = 0; else do { if ((ret = i_stream_read(stream->parent)) == -2) return -2; stream->istream.stream_errno = stream->parent->stream_errno; stream->istream.eof = stream->parent->eof; stream->buffer = i_stream_get_data(stream->parent, &pos); /* check again, in case the parent stream had been seeked backwards and the previous read() didn't get us far enough. */ } while (pos <= stream->pos && ret > 0); ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : (ret == 0 ? 0 : -1); stream->pos = pos; i_assert(ret != -1 || stream->istream.eof || stream->istream.stream_errno != 0); return ret; }
static ssize_t i_stream_tee_read(struct istream_private *stream) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; struct istream *input = tstream->tee->input; const unsigned char *data; size_t size; uoff_t last_high_offset; ssize_t ret; tstream->last_read_waiting = FALSE; if (stream->buffer == NULL) { /* initial read */ tee_streams_update_buffer(tstream->tee); } data = i_stream_get_data(input, &size); /* last_high_offset contains how far we have read this child tee stream so far. input->v_offset + size contains how much is available in the parent stream without having to read more. */ last_high_offset = stream->istream.v_offset + (stream->pos - stream->skip); if (stream->pos == size) { /* we've read everything, need to read more */ i_assert(last_high_offset == input->v_offset + size); tee_streams_skip(tstream->tee); ret = i_stream_read(input); if (ret <= 0) { size = i_stream_get_data_size(input); if (ret == -2 && stream->skip != 0) { /* someone else is holding the data, wait for it */ tstream->last_read_waiting = TRUE; return 0; } stream->istream.stream_errno = input->stream_errno; stream->istream.eof = input->eof; return ret; } tee_streams_update_buffer(tstream->tee); data = i_stream_get_data(input, &size); } else { /* there's still some data available from parent */ i_assert(last_high_offset < input->v_offset + size); tee_streams_update_buffer(tstream->tee); i_assert(stream->pos < size); } i_assert(stream->buffer == data); ret = size - stream->pos; i_assert(ret > 0); stream->pos = size; i_assert(stream->istream.v_offset + (stream->pos - stream->skip) == input->v_offset + size); return ret; }
static void test_istream_children(void) { struct istream *parent, *child1, *child2; const unsigned char *data; size_t size; test_begin("istream children"); parent = test_istream_create_data("123456789", 9); test_istream_set_max_buffer_size(parent, 3); child1 = i_stream_create_limit(parent, (uoff_t)-1); child2 = i_stream_create_limit(parent, (uoff_t)-1); /* child1 read beginning */ test_assert(i_stream_read(child1) == 3); data = i_stream_get_data(child1, &size); test_assert(size == 3 && memcmp(data, "123", 3) == 0); i_stream_skip(child1, 3); /* child1 read middle.. */ test_assert(i_stream_read(child1) == 3); data = i_stream_get_data(child1, &size); test_assert(size == 3 && memcmp(data, "456", 3) == 0); /* child2 read beginning.. */ test_assert(i_stream_read(child2) == 3); data = i_stream_get_data(child2, &size); test_assert(size == 3 && memcmp(data, "123", 3) == 0); /* child1 check middle again.. the parent has been modified, so it can't return the original data (without some code changes). */ test_assert(i_stream_get_data_size(child1) == 0); i_stream_skip(child1, 3); /* child1 read end */ test_assert(i_stream_read(child1) == 3); data = i_stream_get_data(child1, &size); test_assert(size == 3 && memcmp(data, "789", 3) == 0); i_stream_skip(child1, 3); test_assert(i_stream_read(child1) == -1); /* child2 check beginning again.. */ test_assert(i_stream_get_data_size(child1) == 0); i_stream_skip(child2, 3); /* child2 read middle */ test_assert(i_stream_read(child2) == 3); data = i_stream_get_data(child2, &size); test_assert(size == 3 && memcmp(data, "456", 3) == 0); i_stream_skip(child2, 3); i_stream_destroy(&child1); i_stream_destroy(&child2); i_stream_destroy(&parent); test_end(); }
static void test_istream_binary_converter(void) { struct istream *datainput, *input; const unsigned char *data; size_t i, size; int ret; test_begin("istream binary converter"); datainput = test_istream_create_data(mail_input, sizeof(mail_input)); test_istream_set_allow_eof(datainput, FALSE); input = i_stream_create_binary_converter(datainput); for (i = 1; i <= sizeof(mail_input); i++) { test_istream_set_size(datainput, i); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == 0); } test_istream_set_allow_eof(datainput, TRUE); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == -1); data = i_stream_get_data(input, &size); test_assert(size == sizeof(mail_output) && memcmp(data, mail_output, size) == 0); i_stream_unref(&input); i_stream_unref(&datainput); test_end(); }
static void test_dsync_proxy_msg_save(void) { static const char *input = "..dotty\n..behavior\nfrom you\n.\nstop"; struct test_dsync_msg_event event; const unsigned char *data; size_t size; test_begin("proxy server msg save"); server->input = i_stream_create_from_data(input, strlen(input)); test_assert(run_cmd("MSG-SAVE", "28492428", "pop3uidl", "saveguid", "874", "33982482882924", "\\Flagged bar \\Answered", "8294284", NULL) == 1); test_assert(test_dsync_worker_next_msg_event(test_worker, &event)); test_assert(event.type == LAST_MSG_TYPE_SAVE); test_assert(event.save_data.received_date == 28492428); test_assert(strcmp(event.save_data.pop3_uidl, "pop3uidl") == 0); test_assert(strcmp(event.save_body, ".dotty\n.behavior\nfrom you") == 0); test_assert(strcmp(event.msg.guid, "saveguid") == 0); test_assert(event.msg.uid == 874); test_assert(event.msg.modseq == 33982482882924); test_assert(event.msg.flags == (MAIL_FLAGGED | MAIL_ANSWERED)); test_assert(strcmp(event.msg.keywords[0], "bar") == 0); test_assert(event.msg.keywords[1] == NULL); test_assert(event.msg.save_date == 8294284); data = i_stream_get_data(server->input, &size); test_assert(size == 4 && memcmp(data, "stop", 4) == 0); i_stream_destroy(&server->input); test_end(); }
size_t i_stream_get_data_size(struct istream *stream) { size_t size; (void)i_stream_get_data(stream, &size); return size; }
static ssize_t i_stream_hash_read(struct istream_private *stream) { struct hash_istream *hstream = (struct hash_istream *)stream; const unsigned char *data; size_t size; uoff_t skip; ssize_t ret; i_stream_seek(stream->parent, stream->parent_start_offset + stream->istream.v_offset); ret = i_stream_read_copy_from_parent(&stream->istream); if (ret > 0 && hstream->hash_context != NULL) { data = i_stream_get_data(&stream->istream, &size); i_assert((size_t)ret <= size); i_assert(stream->istream.v_offset <= hstream->high_offset); skip = hstream->high_offset - stream->istream.v_offset; if (skip < (size_t)size) { hstream->high_offset += (size-skip); hstream->method->loop(hstream->hash_context, data+skip, size-skip); } } else if (ret < 0) { /* we finished hashing it. don't access it anymore, because the memory pointed by the hash may be freed before the istream itself */ hstream->hash_context = NULL; } return ret; }
static void decode_test(const char *base64_input, const char *output, bool broken_input) { unsigned int base64_input_len = strlen(base64_input); struct istream *input_data, *input; const unsigned char *data; size_t i, size; int ret = 0; input_data = test_istream_create_data(base64_input, base64_input_len); test_istream_set_allow_eof(input_data, FALSE); input = i_stream_create_base64_decoder(input_data); for (i = 1; i <= base64_input_len; i++) { test_istream_set_size(input_data, i); while ((ret = i_stream_read(input)) > 0) ; if (ret == -1 && broken_input) break; test_assert(ret == 0); } if (ret == 0) { test_istream_set_allow_eof(input_data, TRUE); while ((ret = i_stream_read(input)) > 0) ; } test_assert(ret == -1); test_assert((input->stream_errno == 0 && !broken_input) || (input->stream_errno == EINVAL && broken_input)); data = i_stream_get_data(input, &size); test_assert(size == strlen(output)); if (size > 0) test_assert(memcmp(data, output, size) == 0); i_stream_unref(&input); i_stream_unref(&input_data); }
static ssize_t i_stream_nonuls_read(struct istream_private *stream) { struct nonuls_istream *nstream = (struct nonuls_istream *)stream; const unsigned char *data, *p; size_t i, size, avail_size; int ret; if ((ret = i_stream_read_parent(stream)) <= 0) return ret; data = i_stream_get_data(stream->parent, &size); if (!i_stream_try_alloc(stream, size, &avail_size)) return -2; if (size > avail_size) size = avail_size; i_assert(size > 0); p = memchr(data, '\0', size); if (p == NULL) { /* no NULs in this block */ memcpy(stream->w_buffer+stream->pos, data, size); } else { i = p-data; memcpy(stream->w_buffer+stream->pos, data, i); for (; i < size; i++) { stream->w_buffer[stream->pos+i] = data[i] == '\0' ? nstream->replace_chr : data[i]; } } stream->pos += size; i_stream_skip(stream->parent, size); return size; }
static void tee_streams_update_buffer(struct tee_istream *tee) { struct tee_child_istream *tstream = tee->children; const unsigned char *data; size_t size, old_used; data = i_stream_get_data(tee->input, &size); for (; tstream != NULL; tstream = tstream->next) { if (tstream->istream.istream.closed) { tstream->istream.skip = tstream->istream.pos = 0; continue; } old_used = tstream->istream.pos - tstream->istream.skip; tstream->istream.buffer = data; i_assert(tstream->istream.istream.v_offset >= tee->input->v_offset); tstream->istream.skip = tstream->istream.istream.v_offset - tee->input->v_offset; i_assert(tstream->istream.skip + old_used <= size); tstream->istream.pos = tstream->istream.skip + old_used; tstream->istream.parent_expected_offset = tee->input->v_offset; tstream->istream.access_counter = tee->input->real_stream->access_counter; } }
static ssize_t i_stream_base64_encoder_read(struct istream_private *stream) { struct base64_encoder_istream *bstream = (struct base64_encoder_istream *)stream; size_t pre_count, post_count, size; int ret; do { ret = i_stream_read_parent(stream); if (ret <= 0) return ret; (void)i_stream_get_data(stream->parent, &size); } while (size < 4 && !stream->parent->eof); /* encode as many lines as fits into destination buffer */ pre_count = stream->pos - stream->skip; while (i_stream_base64_try_encode_line(bstream)) ; post_count = stream->pos - stream->skip; if (pre_count == post_count) { i_assert(stream->buffer_size - stream->pos < 4); return -2; } i_assert(post_count > pre_count); return post_count - pre_count; }
static const struct stat * i_stream_bzlib_stat(struct istream_private *stream, bool exact) { struct bzlib_istream *zstream = (struct bzlib_istream *) stream; const struct stat *st; size_t size; st = i_stream_stat(stream->parent, exact); if (st == NULL) return NULL; if (zstream->eof_offset == (uoff_t)-1 && !exact) return st; stream->statbuf = *st; if (zstream->eof_offset == (uoff_t)-1) { uoff_t old_offset = stream->istream.v_offset; do { (void)i_stream_get_data(&stream->istream, &size); i_stream_skip(&stream->istream, size); } while (i_stream_read(&stream->istream) > 0); i_stream_seek(&stream->istream, old_offset); if (zstream->eof_offset == (uoff_t)-1) return NULL; } stream->statbuf.st_size = zstream->eof_offset; return &stream->statbuf; }
static void test_istream_base64_encoder_seek(const char *textin, const char *textout) { unsigned int offset, len = strlen(textout); struct istream *input, *input_data; const unsigned char *data; size_t size; ssize_t ret; input_data = i_stream_create_from_data(textin, strlen(textin)); input = i_stream_create_base64_encoder(input_data, 4, TRUE); while (i_stream_read(input) > 0) ; i_stream_skip(input, i_stream_get_data_size(input)); for (offset = 0; offset < len; offset++) { i_stream_seek(input, offset); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == -1); data = i_stream_get_data(input, &size); test_assert(size == len-offset); test_assert(memcmp(data, textout+offset, size) == 0); i_stream_skip(input, size); } i_stream_unref(&input); i_stream_unref(&input_data); }
static ssize_t i_stream_base64_decoder_read(struct istream_private *stream) { struct base64_decoder_istream *bstream = (struct base64_decoder_istream *)stream; const unsigned char *data; size_t pre_count, post_count, size; int ret; do { ret = i_stream_read_parent(stream); if (ret <= 0) { if (ret < 0 && stream->istream.stream_errno == 0 && i_stream_get_data_size(stream->parent) > 0) { /* base64 input with a partial block */ data = i_stream_get_data(stream->parent, &size); io_stream_set_error(&stream->iostream, "base64 input ends with a partial block: 0x%s", binary_to_hex(data, size)); stream->istream.stream_errno = EINVAL; } return ret; } /* encode as many blocks as fits into destination buffer */ pre_count = stream->pos - stream->skip; while ((ret = i_stream_base64_try_decode_block(bstream)) > 0) ; post_count = stream->pos - stream->skip; } while (ret == 0 && pre_count == post_count); if (ret < 0 && pre_count == post_count) return ret; i_assert(post_count > pre_count); return post_count - pre_count; }
static void encode_test(const char *text, unsigned int chars_per_line, bool crlf, const char *output) { unsigned int i, text_len = strlen(text); struct istream *input, *input_data; const unsigned char *data; size_t size; ssize_t ret; input_data = test_istream_create_data(text, text_len); test_istream_set_allow_eof(input_data, FALSE); input = i_stream_create_base64_encoder(input_data, chars_per_line, crlf); for (i = 1; i <= text_len; i++) { test_istream_set_size(input_data, i); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == 0); } test_istream_set_allow_eof(input_data, TRUE); while ((ret = i_stream_read(input)) > 0) ; test_assert(ret == -1); data = i_stream_get_data(input, &size); test_assert(size == strlen(output) && memcmp(data, output, size) == 0); i_stream_unref(&input); i_stream_unref(&input_data); }
static void test_ostream_dot_one(const struct dot_test *test) { struct istream *test_input; struct ostream *output, *test_output; buffer_t *output_data; const unsigned char *data; size_t size; ssize_t ret; test_input = test_istream_create(test->input); output_data = buffer_create_dynamic(pool_datastack_create(), 1024); test_output = o_stream_create_buffer(output_data); output = o_stream_create_dot(test_output, FALSE); while ((ret = i_stream_read(test_input)) > 0 || ret == -2) { data = i_stream_get_data(test_input, &size); ret = o_stream_send(output, data, size); test_assert(ret >= 0); if (ret <= 0) break; i_stream_skip(test_input, ret); } test_assert(test_input->eof); test_assert(o_stream_flush(output) > 0); o_stream_unref(&output); o_stream_unref(&test_output); test_assert(strcmp(str_c(output_data), test->output) == 0); i_stream_unref(&test_input); }
static int json_parser_read_more(struct json_parser *parser) { uoff_t cur_highwater = parser->input->v_offset + i_stream_get_data_size(parser->input); size_t size; ssize_t ret; i_assert(parser->highwater_offset <= cur_highwater); if (parser->error != NULL) return -1; if (parser->highwater_offset == cur_highwater) { ret = i_stream_read(parser->input); if (ret == -2) { parser->error = "Token too large"; return -1; } if (ret <= 0) return ret; cur_highwater = parser->input->v_offset + i_stream_get_data_size(parser->input); i_assert(parser->highwater_offset < cur_highwater); parser->highwater_offset = cur_highwater; } parser->start = parser->data = i_stream_get_data(parser->input, &size); parser->end = parser->start + size; i_assert(size > 0); return 1; }
static int program_client_program_output(struct program_client *pclient) { struct istream *input = pclient->input; struct ostream *output = pclient->program_output; const unsigned char *data; size_t size; int ret = 0; if ((ret = o_stream_flush(output)) <= 0) { if (ret < 0) program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO); return ret; } if ( input != NULL && output != NULL ) { do { while ( (data=i_stream_get_data(input, &size)) != NULL ) { ssize_t sent; if ( (sent=o_stream_send(output, data, size)) < 0 ) { program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO); return -1; } if ( sent == 0 ) return 0; i_stream_skip(input, sent); } } while ( (ret=i_stream_read(input)) > 0 ); if ( ret == 0 ) return 1; if ( ret < 0 ) { if ( !input->eof ) { program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO); return -1; } else if ( !i_stream_have_bytes_left(input) ) { i_stream_unref(&pclient->input); input = NULL; if ( (ret = o_stream_flush(output)) <= 0 ) { if ( ret < 0 ) program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO); return ret; } } } } if ( input == NULL ) { if ( !program_client_input_pending(pclient) ) { program_client_disconnect(pclient, FALSE); } else if (program_client_close_output(pclient) < 0) { program_client_fail(pclient, PROGRAM_CLIENT_ERROR_IO); } } return 1; }
static ssize_t i_stream_limit_read(struct istream_private *stream) { struct limit_istream *lstream = (struct limit_istream *) stream; uoff_t left; ssize_t ret; size_t pos; i_stream_seek(stream->parent, lstream->istream.parent_start_offset + stream->istream.v_offset); if (stream->istream.v_offset + (stream->pos - stream->skip) >= lstream->v_size) { stream->istream.eof = TRUE; return -1; } stream->pos -= stream->skip; stream->skip = 0; stream->buffer = i_stream_get_data(stream->parent, &pos); if (pos > stream->pos) ret = 0; else do { if ((ret = i_stream_read(stream->parent)) == -2) return -2; stream->istream.stream_errno = stream->parent->stream_errno; stream->istream.eof = stream->parent->eof; stream->buffer = i_stream_get_data(stream->parent, &pos); } while (pos <= stream->pos && ret > 0); if (lstream->v_size != (uoff_t)-1) { left = lstream->v_size - stream->istream.v_offset; if (pos >= left) { pos = left; stream->istream.eof = TRUE; } } ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : (ret == 0 ? 0 : -1); stream->pos = pos; i_assert(ret != -1 || stream->istream.eof || stream->istream.stream_errno != 0); return ret; }
void login_proxy_detach(struct login_proxy *proxy) { struct client *client = proxy->client; const unsigned char *data; size_t size; i_assert(proxy->client_fd == -1); i_assert(proxy->server_input != NULL); i_assert(proxy->server_output != NULL); if (proxy->to != NULL) timeout_remove(&proxy->to); proxy->client_fd = i_stream_get_fd(client->input); proxy->client_input = client->input; proxy->client_output = client->output; i_stream_set_persistent_buffers(client->input, FALSE); o_stream_set_max_buffer_size(client->output, (size_t)-1); o_stream_set_flush_callback(client->output, proxy_client_output, proxy); client->input = NULL; client->output = NULL; /* send all pending client input to proxy */ data = i_stream_get_data(proxy->client_input, &size); if (size != 0) o_stream_nsend(proxy->server_output, data, size); /* from now on, just do dummy proxying */ io_remove(&proxy->server_io); proxy->server_io = io_add(proxy->server_fd, IO_READ, server_input, proxy); proxy->client_io = io_add_istream(proxy->client_input, proxy_client_input, proxy); o_stream_set_flush_callback(proxy->server_output, server_output, proxy); i_stream_destroy(&proxy->server_input); if (proxy->notify_refresh_secs != 0) { proxy->to_notify = timeout_add(proxy->notify_refresh_secs * 1000, login_proxy_notify, proxy); } proxy->callback = NULL; if (login_proxy_ipc_server == NULL) { login_proxy_ipc_server = ipc_server_init(LOGIN_PROXY_IPC_PATH, LOGIN_PROXY_IPC_NAME, login_proxy_ipc_cmd); } DLLIST_REMOVE(&login_proxies_pending, proxy); DLLIST_PREPEND(&login_proxies, proxy); client->fd = -1; client->login_proxy = NULL; }
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; }
static int i_stream_base64_try_encode_line(struct base64_encoder_istream *bstream) { struct istream_private *stream = &bstream->istream; const unsigned char *data; size_t size, avail, buffer_avail; buffer_t buf; data = i_stream_get_data(stream->parent, &size); if (size == 0 || (size < 3 && !stream->parent->eof)) return 0; if (bstream->cur_line_len == bstream->chars_per_line) { /* @UNSAFE: end of line, add newline */ if (!i_stream_try_alloc(stream, bstream->crlf ? 2 : 1, &avail)) return -2; if (bstream->crlf) stream->w_buffer[stream->pos++] = '\r'; stream->w_buffer[stream->pos++] = '\n'; bstream->cur_line_len = 0; } i_stream_try_alloc(stream, (size+2)/3*4, &avail); buffer_avail = stream->buffer_size - stream->pos; if ((size + 2) / 3 * 4 > buffer_avail) { /* can't fit everything to destination buffer. write as much as we can. */ size = (buffer_avail / 4) * 3; if (size == 0) return -2; } else if (!stream->parent->eof && size % 3 != 0) { /* encode 3 chars at a time, so base64_encode() doesn't add '=' characters in the middle of the stream */ size -= (size % 3); } i_assert(size != 0); if (bstream->cur_line_len + (size+2)/3*4 > bstream->chars_per_line) { size = (bstream->chars_per_line - bstream->cur_line_len)/4 * 3; i_assert(size != 0); } buffer_create_from_data(&buf, stream->w_buffer + stream->pos, buffer_avail); base64_encode(data, size, &buf); i_assert(buf.used > 0); bstream->cur_line_len += buf.used; i_assert(bstream->cur_line_len <= bstream->chars_per_line); stream->pos += buf.used; i_stream_skip(stream->parent, size); return 1; }
static int i_stream_read_parent(struct istream_private *stream) { size_t size; ssize_t ret; (void)i_stream_get_data(stream->parent, &size); if (size >= 4) return 1; /* we have less than one base64 block. see if there is more data available. */ ret = i_stream_read(stream->parent); if (ret <= 0) { stream->istream.stream_errno = stream->parent->stream_errno; stream->istream.eof = stream->parent->eof; return size > 0 ? 1 : ret; } (void)i_stream_get_data(stream->parent, &size); i_assert(size != 0); return 1; }
static void i_stream_tee_sync(struct istream_private *stream) { struct tee_child_istream *tstream = (struct tee_child_istream *)stream; size_t size; tee_streams_skip(tstream->tee); (void)i_stream_get_data(tstream->tee->input, &size); if (size != 0) { i_panic("tee-istream: i_stream_sync() called " "with data still buffered"); } i_stream_sync(tstream->tee->input); }
static int parse_part_finish(struct message_parser_ctx *ctx, struct message_boundary *boundary, struct message_block *block_r, bool first_line) { struct message_part *part; size_t line_size; i_assert(ctx->last_boundary == NULL); /* get back to parent MIME part, summing the child MIME part sizes into parent's body sizes */ for (part = ctx->part; part != boundary->part; part = part->parent) { message_size_add(&part->parent->body_size, &part->body_size); message_size_add(&part->parent->body_size, &part->header_size); } i_assert(part != NULL); ctx->part = part; if (boundary->epilogue_found) { /* this boundary isn't needed anymore */ ctx->boundaries = boundary->next; } else { /* forget about the boundaries we possibly skipped */ ctx->boundaries = boundary; } /* the boundary itself should already be in buffer. add that. */ block_r->data = i_stream_get_data(ctx->input, &block_r->size); i_assert(block_r->size >= ctx->skip); block_r->data += ctx->skip; /* [[\r]\n]--<boundary>[--] */ if (first_line) line_size = 0; else if (block_r->data[0] == '\r') { i_assert(block_r->data[1] == '\n'); line_size = 2; } else { i_assert(block_r->data[0] == '\n'); line_size = 1; } line_size += 2 + boundary->len + (boundary->epilogue_found ? 2 : 0); i_assert(block_r->size >= ctx->skip + line_size); block_r->size = line_size; parse_body_add_block(ctx, block_r); ctx->parse_next_block = parse_next_body_skip_boundary_line; if ((ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0) return 1; return ctx->parse_next_block(ctx, block_r); }
static int memcached_input_get(struct memcached_connection *conn) { const unsigned char *data; size_t size; uint32_t body_len, value_pos; uint16_t key_len, key_pos, status; uint8_t extras_len, data_type; data = i_stream_get_data(conn->conn.input, &size); if (size < MEMCACHED_REPLY_HDR_LENGTH) return 0; if (data[0] != MEMCACHED_REPLY_HDR_MAGIC) { i_error("memcached: Invalid reply magic: %u != %u", data[0], MEMCACHED_REPLY_HDR_MAGIC); return -1; } memcpy(&body_len, data+8, 4); body_len = ntohl(body_len); body_len += MEMCACHED_REPLY_HDR_LENGTH; if (size < body_len) { /* we haven't read the whole response yet */ return 0; } memcpy(&key_len, data+2, 2); key_len = ntohs(key_len); extras_len = data[4]; data_type = data[5]; memcpy(&status, data+6, 2); status = ntohs(status); if (data_type != MEMCACHED_DATA_TYPE_RAW) { i_error("memcached: Unsupported data type: %u != %u", data[0], MEMCACHED_DATA_TYPE_RAW); return -1; } key_pos = MEMCACHED_REPLY_HDR_LENGTH + extras_len; value_pos = key_pos + key_len; if (value_pos > body_len) { i_error("memcached: Invalid key/extras lengths"); return -1; } conn->reply.value = data + value_pos; conn->reply.value_len = body_len - value_pos; conn->reply.status = status; i_stream_skip(conn->conn.input, body_len); conn->reply.reply_received = TRUE; if (conn->dict->ioloop != NULL) io_loop_stop(conn->dict->ioloop); return 1; }
static bool read_from_buffer(struct seekable_istream *sstream, ssize_t *ret_r) { struct istream_private *stream = &sstream->istream; const unsigned char *data; size_t size, avail_size; if (stream->pos < sstream->buffer_peak) { /* This could be the first read() or we could have already seeked backwards. */ i_assert(stream->pos == 0 && stream->skip == 0); stream->skip = stream->istream.v_offset; stream->pos = sstream->buffer_peak; size = stream->pos - stream->skip; } else { /* need to read more */ i_assert(stream->pos == sstream->buffer_peak); size = sstream->cur_input == NULL ? 0 : i_stream_get_data_size(sstream->cur_input); if (size == 0) { /* read more to buffer */ *ret_r = read_more(sstream); if (*ret_r == 0 || *ret_r == -1) return TRUE; } /* we should have more now. */ data = i_stream_get_data(sstream->cur_input, &size); i_assert(size > 0); /* change skip to 0 temporarily so i_stream_try_alloc() won't try to compress the buffer. */ size_t old_skip = stream->skip; stream->skip = 0; bool have_space = i_stream_try_alloc(stream, size, &avail_size); stream->skip = old_skip; if (!have_space) return FALSE; if (size > avail_size) size = avail_size; memcpy(stream->w_buffer + stream->pos, data, size); stream->pos += size; sstream->buffer_peak += size; i_stream_skip(sstream->cur_input, size); } *ret_r = size; i_assert(*ret_r > 0); return TRUE; }
static ssize_t i_stream_rawlog_read(struct istream_private *stream) { struct rawlog_istream *rstream = (struct rawlog_istream *)stream; ssize_t ret; size_t pos; i_stream_seek(stream->parent, rstream->istream.parent_start_offset + stream->istream.v_offset); stream->pos -= stream->skip; stream->skip = 0; stream->buffer = i_stream_get_data(stream->parent, &pos); if (pos > stream->pos) ret = 0; else do { if ((ret = i_stream_read(stream->parent)) == -2) return -2; stream->istream.stream_errno = stream->parent->stream_errno; stream->istream.eof = stream->parent->eof; stream->buffer = i_stream_get_data(stream->parent, &pos); } while (pos <= stream->pos && ret > 0); if (pos <= stream->pos) ret = ret == 0 ? 0 : -1; else { ret = (ssize_t)(pos - stream->pos); iostream_rawlog_write(&rstream->riostream, stream->buffer + stream->pos, ret); } stream->pos = pos; i_assert(ret != -1 || stream->istream.eof || stream->istream.stream_errno != 0); return ret; }
int i_stream_read_data(struct istream *stream, const unsigned char **data_r, size_t *size_r, size_t threshold) { ssize_t ret = 0; bool read_more = FALSE; do { *data_r = i_stream_get_data(stream, size_r); if (*size_r > threshold) return 1; /* we need more data */ ret = i_stream_read(stream); if (ret > 0) read_more = TRUE; } while (ret > 0); *data_r = i_stream_get_data(stream, size_r); if (ret == -2) return -2; if (ret == 0) { /* need to read more */ i_assert(!stream->blocking); return 0; } if (stream->eof) { if (read_more) { /* we read at least some new data */ return 0; } } else { i_assert(stream->stream_errno != 0); } return -1; }
static void imap_zlib_client_skip_line(struct client *client) { const unsigned char *data; size_t data_size; data = i_stream_get_data(client->input, &data_size); i_assert(data_size > 0); if (data[0] == '\n') i_stream_skip(client->input, 1); else if (data[0] == '\r' && data_size > 1 && data[1] == '\n') i_stream_skip(client->input, 2); else i_unreached(); client->input_skip_line = FALSE; }