-#include "imio.h"
+#include "imager.h"
#include "iolayer.h"
+#include "imerror.h"
#include "log.h"
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#endif
#include <string.h>
+#include <errno.h>
#define IOL_DEB(x)
char *io_type_names[] = { "FDSEEK", "FDNOSEEK", "BUFFER", "CBSEEK", "CBNOSEEK", "BUFCHAIN" };
+typedef struct io_blink {
+ char buf[BBSIZ];
+ /* size_t cnt; */
+ size_t len; /* How large is this buffer = BBZIS for now */
+ struct io_blink *next;
+ struct io_blink *prev;
+} io_blink;
+
+
+/* Structures that describe callback interfaces */
+
+typedef struct {
+ off_t offset;
+ off_t cpos;
+} io_ex_rseek;
+
+
+typedef struct {
+ off_t offset;
+ off_t cpos;
+ io_blink *head;
+ io_blink *tail;
+ io_blink *cp;
+} io_ex_fseek;
+
+
+typedef struct {
+ off_t offset; /* Offset of the source - not used */
+ off_t length; /* Total length of chain in bytes */
+ io_blink *head; /* Start of chain */
+ io_blink *tail; /* End of chain */
+ off_t tfill; /* End of stream in last link */
+ io_blink *cp; /* Current element of list */
+ off_t cpos; /* Offset within the current */
+ off_t gpos; /* Global position in stream */
+} io_ex_bchain;
+
+typedef struct {
+ off_t offset; /* Offset of the source - not used */
+ off_t cpos; /* Offset within the current */
+} io_ex_buffer;
+
+static void io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata);
+static void io_obj_setp_cb2 (io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb);
+
/*
=head1 NAME
static off_t fd_seek(io_glue *ig, off_t offset, int whence);
static void fd_close(io_glue *ig);
static ssize_t fd_size(io_glue *ig);
+static const char *my_strerror(int err);
/*
* Callbacks for sources that cannot seek
=cut
*/
-void
-io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb, void *closedata) {
+static void
+io_obj_setp_buffer(io_obj *io, char *p, size_t len, closebufp closecb,
+ void *closedata) {
io->buffer.type = BUFFER;
io->buffer.data = p;
io->buffer.len = len;
}
-/*
-=item io_obj_setp_buchain(io)
-
-Sets an io_object for reading/writing from a buffer source
-
- io - io object that describes a source
- p - pointer to buffer
- len - length of buffer
-
-=cut
-*/
-
-void
-io_obj_setp_bufchain(io_obj *io) {
- io->type = BUFCHAIN;
-}
-
/*
=item io_obj_setp_cb2(io, p, readcb, writecb, seekcb, closecb, destroycb)
=cut
*/
-void
+static void
io_obj_setp_cb2(io_obj *io, void *p, readl readcb, writel writecb, seekl seekcb, closel closecb, destroyl destroycb) {
io->cb.type = CBSEEK;
io->cb.p = p;
io->cb.destroycb = destroycb;
}
-void
-io_obj_setp_cb(io_obj *io, void *p, readl readcb, writel writecb,
- seekl seekcb) {
- io_obj_setp_cb2(io, p, readcb, writecb, seekcb, NULL, NULL);
-}
-
/*
=item io_glue_commit_types(ig)
-Creates buffers and initializes structures to read with the chosen interface.
-
- ig - io_glue object
+This is now effectively a no-op.
=cut
*/
return;
}
- switch (inn) {
- case BUFCHAIN:
- {
- io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
-
- ieb->offset = 0;
- ieb->length = 0;
- ieb->cpos = 0;
- ieb->gpos = 0;
- ieb->tfill = 0;
-
- ieb->head = io_blink_new();
- ieb->cp = ieb->head;
- ieb->tail = ieb->head;
-
- ig->exdata = ieb;
- ig->readcb = bufchain_read;
- ig->writecb = bufchain_write;
- ig->seekcb = bufchain_seek;
- ig->closecb = bufchain_close;
- }
- break;
- case CBSEEK:
- {
- io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
-
- ier->offset = 0;
- ier->cpos = 0;
-
- ig->exdata = ier;
- ig->readcb = realseek_read;
- ig->writecb = realseek_write;
- ig->seekcb = realseek_seek;
- ig->closecb = realseek_close;
- }
- break;
- case BUFFER:
- {
- io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
- ieb->offset = 0;
- ieb->cpos = 0;
-
- ig->exdata = ieb;
- ig->readcb = buffer_read;
- ig->writecb = buffer_write;
- ig->seekcb = buffer_seek;
- ig->closecb = buffer_close;
- }
- break;
- case FDSEEK:
- {
- ig->exdata = NULL;
- ig->readcb = fd_read;
- ig->writecb = fd_write;
- ig->seekcb = fd_seek;
- ig->closecb = fd_close;
- break;
- }
- }
ig->flags |= 0x01; /* indicate source has been setup already */
}
io_glue *
io_new_bufchain() {
io_glue *ig;
+ io_ex_bchain *ieb = mymalloc(sizeof(io_ex_bchain));
+
mm_log((1, "io_new_bufchain()\n"));
+
ig = mymalloc(sizeof(io_glue));
memset(ig, 0, sizeof(*ig));
- io_obj_setp_bufchain(&ig->source);
- return ig;
-}
-
-
+ ig->source.type = BUFCHAIN;
+ ieb->offset = 0;
+ ieb->length = 0;
+ ieb->cpos = 0;
+ ieb->gpos = 0;
+ ieb->tfill = 0;
+
+ ieb->head = io_blink_new();
+ ieb->cp = ieb->head;
+ ieb->tail = ieb->head;
+
+ ig->exdata = ieb;
+ ig->readcb = bufchain_read;
+ ig->writecb = bufchain_write;
+ ig->seekcb = bufchain_seek;
+ ig->closecb = bufchain_close;
+ return ig;
+}
/*
=item io_new_buffer(data, len)
io_glue *
io_new_buffer(char *data, size_t len, closebufp closecb, void *closedata) {
io_glue *ig;
+ io_ex_buffer *ieb = mymalloc(sizeof(io_ex_buffer));
+
mm_log((1, "io_new_buffer(data %p, len %d, closecb %p, closedata %p)\n", data, len, closecb, closedata));
+
ig = mymalloc(sizeof(io_glue));
memset(ig, 0, sizeof(*ig));
io_obj_setp_buffer(&ig->source, data, len, closecb, closedata);
ig->flags = 0;
+
+ ieb->offset = 0;
+ ieb->cpos = 0;
+
+ ig->exdata = ieb;
+ ig->readcb = buffer_read;
+ ig->writecb = buffer_write;
+ ig->seekcb = buffer_seek;
+ ig->closecb = buffer_close;
+
return ig;
}
io_glue *
io_new_fd(int fd) {
io_glue *ig;
+
mm_log((1, "io_new_fd(fd %d)\n", fd));
+
ig = mymalloc(sizeof(io_glue));
memset(ig, 0, sizeof(*ig));
ig->source.type = FDSEEK;
ig->source.fdseek.fd = fd;
ig->flags = 0;
-#if 0
-#ifdef _MSC_VER
- io_obj_setp_cb(&ig->source, (void*)fd, _read, _write, _lseek);
-#else
- io_obj_setp_cb(&ig->source, (void*)fd, read, write, lseek);
-#endif
-#endif
+
+ ig->exdata = NULL;
+ ig->readcb = fd_read;
+ ig->writecb = fd_write;
+ ig->seekcb = fd_seek;
+ ig->closecb = fd_close;
+ ig->sizecb = fd_size;
+
mm_log((1, "(%p) <- io_new_fd\n", ig));
return ig;
}
io_glue *io_new_cb(void *p, readl readcb, writel writecb, seekl seekcb,
closel closecb, destroyl destroycb) {
io_glue *ig;
+ io_ex_rseek *ier = mymalloc(sizeof(io_ex_rseek));
mm_log((1, "io_new_cb(p %p, readcb %p, writecb %p, seekcb %p, closecb %p, "
"destroycb %p)\n", p, readcb, writecb, seekcb, closecb, destroycb));
io_obj_setp_cb2(&ig->source, p, readcb, writecb, seekcb, closecb, destroycb);
mm_log((1, "(%p) <- io_new_cb\n", ig));
+ ier->offset = 0;
+ ier->cpos = 0;
+
+ ig->exdata = ier;
+ ig->readcb = realseek_read;
+ ig->writecb = realseek_write;
+ ig->seekcb = realseek_seek;
+ ig->closecb = realseek_close;
+
return ig;
}
=cut
*/
static ssize_t fd_read(io_glue *ig, void *buf, size_t count) {
+ ssize_t result;
#ifdef _MSC_VER
- return _read(ig->source.fdseek.fd, buf, count);
+ result = _read(ig->source.fdseek.fd, buf, count);
#else
- return read(ig->source.fdseek.fd, buf, count);
+ result = read(ig->source.fdseek.fd, buf, count);
#endif
+
+ /* 0 is valid - means EOF */
+ if (result < 0) {
+ i_push_errorf(0, "read() failure: %s (%d)", my_strerror(errno), errno);
+ }
+
+ return result;
}
static ssize_t fd_write(io_glue *ig, const void *buf, size_t count) {
+ ssize_t result;
#ifdef _MSC_VER
- return _write(ig->source.fdseek.fd, buf, count);
+ result = _write(ig->source.fdseek.fd, buf, count);
#else
- return write(ig->source.fdseek.fd, buf, count);
+ result = write(ig->source.fdseek.fd, buf, count);
#endif
+
+ if (result <= 0) {
+ i_push_errorf(errno, "write() failure: %s (%d)", my_strerror(errno), errno);
+ }
+
+ return result;
}
static off_t fd_seek(io_glue *ig, off_t offset, int whence) {
+ off_t result;
#ifdef _MSC_VER
- return _lseek(ig->source.fdseek.fd, offset, whence);
+ result = _lseek(ig->source.fdseek.fd, offset, whence);
#else
- return lseek(ig->source.fdseek.fd, offset, whence);
+ result = lseek(ig->source.fdseek.fd, offset, whence);
#endif
+
+ if (result == (off_t)-1) {
+ i_push_errorf(errno, "lseek() failure: %s (%d)", my_strerror(errno), errno);
+ }
+
+ return result;
}
static void fd_close(io_glue *ig) {
myfree(ig);
}
+/*
+=back
+
+=head1 INTERNAL FUNCTIONS
+
+=over
+
+=item my_strerror
+
+Calls strerror() and ensures we don't return NULL.
+
+On some platforms it's possible for strerror() to return NULL, this
+wrapper ensures we only get non-NULL values.
+
+=cut
+*/
+
+static
+const char *my_strerror(int err) {
+ const char *result = strerror(err);
+
+ if (!result)
+ result = "Unknown error";
+
+ return result;
+}
/*
=back