ssize_t (*writev)(struct file_ostream *fstream,
const struct const_iovec *iov,
- unsigned int iov_count);
+ unsigned int iov_count, const char **error_r);
int fd;
struct io *io;
o_stream_create_file_common(struct file_ostream *fstream,
int fd, size_t max_buffer_size, bool autoclose_fd);
ssize_t o_stream_file_writev(struct file_ostream *fstream,
- const struct const_iovec *iov,
- unsigned int iov_size);
+ const struct const_iovec *iov,
+ unsigned int iov_size, const char **error_r);
ssize_t o_stream_file_sendv(struct ostream_private *stream,
const struct const_iovec *iov,
unsigned int iov_count);
}
ssize_t o_stream_file_writev(struct file_ostream *fstream,
- const struct const_iovec *iov,
- unsigned int iov_count)
+ const struct const_iovec *iov,
+ unsigned int iov_count,
+ const char **error_r)
{
+ const char *syscall = NULL;
ssize_t ret;
size_t size, sent;
unsigned int i;
if (!fstream->file ||
fstream->real_offset == fstream->buffer_offset) {
+ syscall = "write";
ret = write(fstream->fd, iov->iov_base, iov->iov_len);
if (ret > 0)
fstream->real_offset += ret;
} else {
+ syscall = "pwrite";
ret = pwrite(fstream->fd, iov->iov_base, iov->iov_len,
fstream->buffer_offset);
}
} else {
- if (o_stream_lseek(fstream) < 0)
+ if (o_stream_lseek(fstream) < 0) {
+ *error_r = t_strdup(o_stream_get_error(&fstream->ostream.ostream));
return -1;
+ }
+ syscall = "writev";
sent = 0;
while (iov_count > IOV_MAX) {
size = 0;
ret = sent;
}
}
+ if (ret < 0) {
+ i_assert(syscall != NULL);
+ *error_r = t_strdup_printf("%s() failed: %m", syscall);
+ }
return ret;
}
const struct const_iovec *iov,
unsigned int iov_count)
{
+ const char *error = NULL;
ssize_t ret, ret2;
size_t size, total_size;
bool partial;
total_size += iov[i].iov_len;
o_stream_socket_cork(fstream);
- ret = fstream->writev(fstream, iov, iov_count);
+ ret = fstream->writev(fstream, iov, iov_count, &error);
partial = ret != (ssize_t)total_size;
if (ret < 0) {
+ i_assert(error != NULL);
if (fstream->file) {
if (errno == EINTR) {
/* automatically retry */
/* try again later */
return 0;
}
+ io_stream_set_error(&fstream->ostream.iostream, "%s", error);
fstream->ostream.ostream.stream_errno = errno;
stream_closed(fstream);
return -1;
}
static ssize_t o_stream_unix_writev(struct file_ostream *fstream,
- const struct const_iovec *iov,
- unsigned int iov_count)
+ const struct const_iovec *iov,
+ unsigned int iov_count,
+ const char **error_r)
{
struct unix_ostream *ustream =
container_of(fstream, struct unix_ostream, fstream);
if (ustream->write_fd == -1) {
/* no fd */
- return o_stream_file_writev(fstream, iov, iov_count);
+ return o_stream_file_writev(fstream, iov, iov_count, error_r);
}
/* send first iovec along with fd */
i_assert(iov[0].iov_len > 0);
ret = fd_send(fstream->fd, ustream->write_fd,
iov[0].iov_base, iov[0].iov_len);
- if (ret < 0)
+ if (ret < 0) {
+ *error_r = t_strdup_printf("fd_send() failed: %m");
return ret;
+ }
/* update stream */
sent = ret;
}
/* send remaining iovecs */
- ret = o_stream_file_writev(fstream, &iov[1], iov_count-1);
+ ret = o_stream_file_writev(fstream, &iov[1], iov_count-1, error_r);
if (ret < 0)
return (errno == EAGAIN || errno == EINTR ? (ssize_t)sent : ret);
sent += ret;