ostream-failure-at.c revision 2bee4c37862d33fe09544d865225d140bd533225
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen#include "buffer.h"
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen#include "ostream-private.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ostream-failure-at.h"
5666a3d6a7ea89362b8d9e8b39b15424cd9d6388Timo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainenstruct failure_at_ostream {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct ostream_private ostream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen char *error_string;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen uoff_t failure_offset;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen bool failed;
573f0491a5733fe21fa062a455acb4790b4e0499Timo Sirainen};
3ed2d0f6b5e67e2663d44489d9da3176823789a8Timo Sirainen
65f8fb656051f1059f7b5a2da9c5555adcc30439Timo Sirainenstatic void o_stream_failure_at_destroy(struct iostream_private *stream)
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen{
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen struct failure_at_ostream *fstream =
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen (struct failure_at_ostream *)stream;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen i_free(fstream->error_string);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen o_stream_unref(&fstream->ostream.parent);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen}
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainenstatic ssize_t
a64adf62fa33f2463a86f990217b0c9078531a40Timo Siraineno_stream_failure_at_sendv(struct ostream_private *stream,
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen const struct const_iovec *iov, unsigned int iov_count)
f7539a17ea306191b53b8f5e752e228937df9ec3Timo Sirainen{
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct failure_at_ostream *fstream =
2dd39e478269d6fb0bb26d12b394aa30ee965e38Timo Sirainen (struct failure_at_ostream *)stream;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int i;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen struct const_iovec *iov_dup;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen unsigned int iov_dup_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen uoff_t bytes_until_failure;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen ssize_t ret;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (fstream->failure_offset <= stream->ostream.offset) {
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen io_stream_set_error(&stream->iostream, "%s",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fstream->error_string);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen stream->ostream.stream_errno = errno = EIO;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen fstream->failed = TRUE;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return -1;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen }
3e564425db51f3921ce4de11859777135fdedd15Timo Sirainen bytes_until_failure = fstream->failure_offset - stream->ostream.offset;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen iov_dup = i_new(struct const_iovec, iov_count);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen iov_dup_count = iov_count;
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen for (i = 0; i < iov_count; i++) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen iov_dup[i] = iov[i];
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen if (iov_dup[i].iov_len >= bytes_until_failure) {
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen iov_dup[i].iov_len = bytes_until_failure;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen iov_dup_count = i+1;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen break;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen ret = o_stream_sendv(stream->parent, iov_dup, iov_dup_count);
e5fd6dfd0a492e4708d4dbb7971d7fc5d7b8fd85Timo Sirainen i_free(iov_dup);
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen if (ret < 0) {
4ba9a1d3facc515b3feb5238a16bcf91f76fac61Timo Sirainen o_stream_copy_error_from_parent(stream);
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen return -1;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen stream->ostream.offset += ret;
57a8c6a95e4bce3eeaba36985adb81c07dd683ffTimo Sirainen return ret;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen}
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
539977f9257bd8985be5a8093658da266ae9cd19Timo Sirainenstatic int
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Siraineno_stream_failure_at_flush(struct ostream_private *stream)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen struct failure_at_ostream *fstream =
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen (struct failure_at_ostream *)stream;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen if (fstream->failed) {
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen io_stream_set_error(&stream->iostream, "%s",
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen fstream->error_string);
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen stream->ostream.stream_errno = errno = EIO;
420040a5930a2b497e79ff0b5f59ba4b764a5b39Timo Sirainen return -1;
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainen }
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen return o_stream_flush(stream->parent);
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen}
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainen
ff7056842f14fd3b30a2d327dfab165b9d15dd30Timo Sirainenstruct ostream *
f1743785713e7632459d623d5df2108f4b93accbTimo Siraineno_stream_create_failure_at(struct ostream *output, uoff_t failure_offset,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen const char *error_string)
70ead6466f9baa8294e71fc2fba0a4f54f488b5eTimo Sirainen{
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen struct failure_at_ostream *fstream;
ccc895c0358108d2304239063e940b7d75f364abTimo Sirainen
8d630c15a8ed6f85553467c3a231a273defca5f6Timo Sirainen fstream = i_new(struct failure_at_ostream, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fstream->ostream.sendv = o_stream_failure_at_sendv;
ee116df08d0fdab703483e18fe8076b2ef9fd9d7Timo Sirainen fstream->ostream.flush = o_stream_failure_at_flush;
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen fstream->ostream.iostream.destroy = o_stream_failure_at_destroy;
c5ab90cfad9cc3e33bcb1baeb30ffc82a7b7053aTimo Sirainen fstream->failure_offset = failure_offset;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen fstream->error_string = i_strdup(error_string);
8e371a3ce32bd64288786855b8ce0cb63f19f7d1Timo Sirainen return o_stream_create(&fstream->ostream, output,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen o_stream_get_fd(output));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainenstruct ostream *
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Siraineno_stream_create_failure_at_flush(struct ostream *output, const char *error_string)
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen{
b9f564d00b7a115f465ffd6840341c7b8f9bfc8aTimo Sirainen struct failure_at_ostream *fstream;
fdc557286bc9f92c5f3bb49096ff6e2bcec0ea79Timo Sirainen
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen fstream = i_new(struct failure_at_ostream, 1);
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen fstream->ostream.flush = o_stream_failure_at_flush;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen fstream->ostream.iostream.destroy = o_stream_failure_at_destroy;
a2f250a332dfc1e6cd4ffd196c621eb9dbf7b8a1Timo Sirainen fstream->error_string = i_strdup(error_string);
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen fstream->failed = TRUE;
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen return o_stream_create(&fstream->ostream, output,
e03d986a74128f5ba30fcfda9f6e36578f5d8decTimo Sirainen o_stream_get_fd(output));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen